본문 바로가기
깡샘 코틀린

04-3 코틀린의 클래스 종류

by 농농씨 2023. 6. 14.

데이터 클래스

data 키워드로 선언

자주 사용하는 데이터를 객체로 묶어줌. VO(value-object) 클래스를 편리하게 이용할 수 있게 해줌.

 

equals() 함수

객체의 데이터를 비교함

VO 클래스는 데이터를 주요하게 다루므로 데이터가 같은지 자주 비교함

❗️'객체가 같은지'가 아니라 객체의 '데이터가 같은지' 를 비교함❗️

// 데이터 클래스 선언 예시
class NonDataClass(val name: String, val email: String, val age: Int) // 일반 클래스

data class DataClass(val name: String, val email: String, val age: Int) // 데이터 클래스
// 두 클래스의 주 생성자는 매개변수 구성이 같음


// 데이터 클래스 객체 생성
fun main() {
	val non1 = NonDataClass("kkang", "a@a.com", 10)
    val non2 = NonDataClass("kkang", "a@a.com", 10)
    
    val data1 = DataClass("kkang", "a@a.com", 10)
    val data2 = DataClass("kkang", "a@a.com", 10)
}


// 객체의 데이터를 비교하는 equals 함수
println("non data class eqals : ${non1.equals(non2)}")
	// equals()함수로 클래스의 객체를 비교하면 '객체 자체'를 비교함
println("data class equals : ${data1.equals(data2)}")
	//     "        데이터 클래스의 객체를 비교하면 객체 자체가 아닌 '객체의 데이터'를 비교함

실행결과:
non data class equals : false
data equals : true

데이터 클래스는 주로 주 생성자에 val, var 키워드로 매개변수를 선언해 클래스의 멤버변수로 활용하는 것이 일반적.

또한, 객체의 데이터를 비교할 때 이용하는 equals() 함수는 주 생성자에 선언한 멤버 변수의 데이터만 비교 대상으로 삼음.

 

// 데이터 클래스의 equals() 함수
data class DataClass(val name: String, val email: String, val age: Int) {
	// 매개변수 세개인 데이터 클래스 선언
	lateinit var address: String // 늦은 초기화('03 코틀린 시작하기' 포스팅 복습)
    constructor(name: String, email: String, age: Int, address: String):
    	this(name, email, age) { // 보조생성자 선언하면서 주 생성자 함께 호출함(필수임)
        this.address = address // 클래스 멤버인 this.address에 보조생성자의 매개변수인 address의 변숫값을 대입함
    }
}
fun main() {
	val obj1 = DataClass("kkang", "a@a.com", 10, "seoul") // 객체생성
    val obj2 = DataClass("kkang", "a@a.com", 10, "busan")
    println("obj1.equals(obj2) : ${obj1.equals(obj2)}") // 두 객체의 값이 같은지 비교 위해 equals() 함수 사용
}

실행결과:
obj1.equals(obj2) : true
더보기

늦은 초기화 복습 : 

lateinit 규칙2가지

:var 키워드로 선언한 변수에만 사용 가능

:Int, Long, Short, Double, Float, Boolean, Byte 타입에 사용 불가(String은 사용가능)

 

위의 두 객체는 일부 멤버 변숫값은 다르지만, 주 생성자에 선언한 멤버 변숫값이 같아서 true 뜸!

즉, 데이터 클래스의 equals()함수는 주 생성자의 멤버 변수가 같은지만 판단한다.

 

 

toString() 함수

객체의 데이터를 반환함

일반 클래스와 데이터 클래스에서 반환값이 다름

// 데이터 클래스와 toString() 함수
fun main() {
	class NonDataClass(val name: String, val email: String, val age: Int) // 일반 클래스 선언
    data class Data(val name: String, val email: String, val age: Int) // 데이터 클래스 선언
    val non = NonDataClass("kkang", "a@a.com", 10) // 일반 클래스 객체 생성
    val data = DataClass("kkang", "a@a.com", 10) // 데이터 클래스 객체 생성
    println("non data class toString : ${non.toString()}") // 일반 클래스 toString() 함수 적용
    println("data class toString : ${data.toString()}") // 데이터 클래스 toString() 함수 적용
}

실행결과:
non data class toString : com.example.test4.ch2.Test2Kt.$miain$NonDataClass@61bbe9ba
data class toString : DataClass(name=kkang, email=a@a.com, age=10)

일반클래스에서의 toString() 함수 출력값은 no 의미.

데이터클래스에서는 '객체가 포함하는 멤버 변수의 데이터를 출력'함➡️ 객체의 데이터 확인할 때 유용

❗️역시 또 주 생성자의 매개변수에 선언된 데이터만 출력 대상!❗️

 

 

오브젝트 클래스

코틀린에서 주로 익명 클래스(anonymous class)를 만들 목적으로 사용됨.

익명 클래스는 말그대로 이름이 없으므로 클래스를 선언하면서 동시에 객체를 생성해야함. 그렇지 않으면 이후에 객체를 생성할 방법이 없음!🫢

// 오브젝트 클래스 사용 예
val obj = object { // 그냥 object라는 키워드 사용. 바로 변수 할당해서 객체 생성해야함~
	var data = 10 // 변수명 뒤에 뒤에 이어서 바로 클래스 본문 써주기~
    fun some() {
    	println("data : $data")
    }
}
fun main() {
	obj.data = 20 // 오류! 허걱~ 
    obj.some() // 오류! 허걱~~~
}

❓왜 객체로 클래스에 선언한 멤버에 접근 할 수 없을까?

✅클래스의 타입을 명시하지 않았기 때문!! 타입 명시 안하면 'Any'로 취급됨. 근데 Any타입 객체에는 data, some() 이라는 멤버가 없어서 오류가 발생함.🤔

😯그래서 object { } 형태로 익명클래스를 선언할 수는 있지만 보통은 타입까지 함께 입력해서 선언함.(오브젝트 클래스의 타입은 object 뒤에 콜론(:)입력하고 뒤에 클래스의 상위 또는 인터페이스 입력)

// 타입을 지정한 오브젝트 클래스
open class Super { // open 키워드 사용해서 클래스 정의
    open var data = 10 // 멤버 변수도 open
    open fun some() {
    	println("I am super some() : $data")
    }
}
val obj = object: Super() { // Super클래스 상속받은 익명클래스 선언과 익명객체 생성
    override var data = 20 // 멤버변수 재정의(오버라이딩)
    override fun some() {
    	println("I am object some() : $data")
    }
}
fun main() {
    obj.data = 30 // 성공~
    obj.some() //성공~
}

obj객체로 Super 클래스에 선언된 멤버에 접근할 수 있게 됨~~

 

 

컴패니언 클래스

멤버 변수나 함수를 클래스 이름으로 접근하고자 할 때 사용함

일반적으로 클래스의 멤버는 객체를 생성해서 접근해야 하는데, 컴패니언 클래스는 객체를 생성하지 않고서도 클래스 이름으로 특정 멤버를 이용할 수 있게 함!

// 일반 클래스의 멤버 접근
class MyClass { // 매개변수 없는 클래스 생성, 생성자도 생략했음
	var data = 10
    fun some() {
    	println(data)
    }
}
fun main() {
	val obj = MyClass() // 객체 생성
    obj.data = 20 // 객체명으로 멤버변수에 접근
    obj.some() // 객체명으로 멤버함수에 접근
    MyClass.data = 20 // 클래스이름으로 접근 ➡️ 오류!!
    MyClass.some() // 오류!
}

일반클래스에서는 클래스이름으로 멤버변수에 접근하면 오류남(객체명으로는 접근 가능)

 

// 컴패니언 클래스의 멤버 접근
class MyClass { // 매개변수 없고 생성자도 생략한, 일반 클래스 선언
	companion object { // companion (+object) 키워드 사용해서 클래스이름으로 멤버에 접근할 수 있게 함
    	var data = 10
        fun some() {
        	println(data)
        }
    }
}
fun main() {
	MyClass.data = 20 // 성공
    MyClass.some() // 성공
}

클래스 내부에 companion object { } 형태로 선언하면 이 클래스를 감싸는 클래스 이름으로 멤버에 접근할 수 있다~

'깡샘 코틀린' 카테고리의 다른 글

05-2 널 안정성  (0) 2023.06.15
05-1 람다 함수와 고차 함수  (0) 2023.06.15
04-2 클래스를 재사용하는 상속  (0) 2023.06.14
04-1 클래스와 생성자  (0) 2023.06.13
03 코틀린 시작하기  (0) 2023.06.06