23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
프로그램을 작성하다 보면, 오직 데이터를 실어 나르기 위한 객체를 만들어할 때가 있다.
이럴때 data class 를 사용하여 클래스를 생성하고, 데이터를 담을 수 있다.
data class Person(val name: String, var age: Int)위와 같이 data class 로 선언한다.
Person은 데이터 클래스의 이름이다.
data class는 name과 age 라는 속성을 가진다.
중요한 포인트는 data class는 copy(), equals(), hashCode(), toString() 에 대한 메소드를 자동으로 미리 구현되어 있다.
개발자가 직접 메소드를 작성할 필요가 없다.
기본 생성자는 무조건 1개 이상의 파라미터가 필요하다.
기본 생성자의 파라미터는 반드시 val(읽기 전용)이나 var(읽기-쓰기 가능) 를 가져야한다.
클래스는 open이 될수 없다. 즉, 상속이 불가능하다.
abstract 도 될수 없다. 즉, 객체의 상속을 의도하지 않기 때문에 추상 클래스도 될 수 없다.
inner이나 sealed 도 될수 없다.
data class를 이제 만들어 보자.
08.01.data_class_sample.kt 파일을 다음과 같이 작성하자.
data class Person(val name: String, var age: Int)
fun main(args: Array<String>) {
val person01 = Person("UncleBae", 40)
println(person01)
println("Name: " + person01.name)
println("Age: " + person01.age)
}결과는 다음과 같다.
Person(name=UncleBae, age=40)
Name: UncleBae
Age: 40자동으로 toString 메소드가 구현되어 있으므로 println로 객체자체를 출력할때 Person(name=UncleBae, age=40) 이 출력되는 것을 확인할 수 있다.
data class는 copy() 함수가 이미 구현되어 있다.
이를 이용하여 원래 data class로 부터 새로운 data class를 복사하고, 원하는 값을 변경할 수 있다.
08.02.data_class_sample.kt 파일을 다음과 같이 작성하자.
data class Person(val name: String, var age: Int)
fun main(args: Array<String>) {
val person01 = Person("UncleBae", 40)
println(person01)
val person02 = person01.copy(name = "Ruby")
println(person02)
}결과는 다음과 같다.
Person(name=UncleBae, age=40)
Person(name=Ruby, age=40)즉, copy 메소드를 이용하여 원래 값에서 이름만 바꾼 새로운 값을 생성하였다.
hashCode() 는 객체 값을 이용하여 해시 코드를 생성한다. 즉, 값의 유니크성을 확인할 수 있도록 해주는 함수이다.
equals() 는 객체 내부의 값이 동일한지 검사한다.
다음과 같이 08.03.data_class_sample.kt 파일을 다음과 같이 작성한다.
data class Person(val name: String, var age: Int)
fun main(args: Array<String>) {
val person01 = Person("UncleBae", 40)
val person02 = person01.copy()
val person03 = person01.copy(name = "Ruby")
println("person01: " + person01.hashCode())
println("person02: " + person02.hashCode())
println("person03: " + person03.hashCode())
println("-----------------------------------------")
if (person01.equals(person02) == true) {
println("U1 is equals to U2")
} else {
println("U1 is not equals to u2")
}
if (person01.equals(person03) == true) {
println("U1 is equals to u3")
} else {
print("U1 is not equals to u3")
}
}결과는 다음과 같다.
person01: 276639557
person02: 276639557
person03: 79312238
-----------------------------------------
U1 is equals to U2
U1 is not equals to u3즉, person01에서 copy를 통해서객체를 그대로 복사했다. 이때 hashCode는 둘다 동일한 값을 가진다.
다만, 복사를 하고 해당 값을 변경하면 다른 값이 불러지게 된다.
데이터 객체로 부터 값을 조회할때 해당 데이터 클래스 값을 분해하여 반환 받을 수 있다.
이를 Destruction이라고 부른다.
08.04.data_class_sample.kt 파일을 다음과 같이 작성하자.
data class Person(val name: String, var age: Int, val gender: String)
fun main(args: Array<String>) {
val person01 = Person("UncleBae", 40, "Male")
val (name, age, gender) = person01
println("Name: " + name)
println("Age: " + age)
println("Gender: " + gender)
}결과는 다음과 같다.
Name: UncleBae
Age: 40
Gender: Malekotlin data class는 자동으로 componentN으로 생성자의 순서대로 값을 가져올 수 있다.
08.05.data_class_sample.kt 파일을 다음과 같이 작성하자.
data class Person(val name: String, var age: Int, val gender: String)
fun main(args: Array<String>) {
val person01 = Person("UncleBae", 40, "Male")
println("Component1: " + person01.component1())
println("Component2: " + person01.component2())
println("Component3: " + person01.component3())
}결과는 다음과 같다.
Component1: UncleBae
Component2: 40
Component3: Maledata class는 순수하게 데이터를 담기 위한 클래스를 정의할때 유용하다.
내부적으로 toString, equals, hashCode, copy, componentN 등의 함수를 미리 작성되어 있기 때문에 반복적인 보일러플레이트 코드를 상당히 줄일 수 있다.
샘플 코드는: https://www.programiz.com/kotlin-programming/data-class 을 참조했다.
sealed 클래스는 값이 제한된 세트 (제한된 계층구조)의 유형중 하나만 가질 수 있을때 사용된다.
class Expr
class Const(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int =
when (e) {
is Const -> e.value
is Sum -> eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}Expr 클래스는 베이스 클래스이다.
Const와 Sum 은 Expr을 상속받은 객체인 것을 알 수 있다.
eval 함수에서 Expr 를 파라미터로 받고, 각 자식 클래스의 타입에 따라 특정 일을 수행할때 when 구문을 이용하고 is 를 통해서 특정 클래스 타입일때 각 작업을 수행할 수 있게 된다.
이외의 값이 들어온다면 else 조건에 따라 IllegalArgumentException 을 반환하게 된다. 이 때 else는 필수이며, 없으면 오류가 난다. w
when 조건식이 기타 케이스를 검출하지 못하기 때문이다.
위 코드에서 만약 Expr을 상속받는 새로운 자식 클래스를 작성한다면, 위 코드는 else에 걸리고, 원하지 않는 오류를 발생 시킬 수 있다.
이때에는 새로운 서브 클래스가 추가될때 컴파일러가 오류를 반환한다면, 누락되는 구현 없이 새로운 서브 클래스에 대한 대응 작업을 하게 된다.
이 때 사용하는 것이 sealed class 이다.
sealed 를 지정하면 위 코드에서 else를 제거하고 좀더 제한적으로 클래스를 사용하도록 할 수 있다.
sealed class Expr
class Const(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
object NotANumber : Expr()
fun eval(e: Expr): Int =
when (e) {
is Const -> e.value
is Sum -> eval(e.right) + eval(e.left)
NotANumber -> java.lang.Double.NaN
}이제 위 코드는 else가 없다.
왜냐하면 sealed 를 지정하여 Expr이 상속받는 클래스는 명확히 Const, Sum, NotANumber 로 규정했기 때문에 더이상의 서브 클래스가 없다고 선언했기 때문이다.
반드시 sealed 를 지정한 동일한 파일에 서브 클래스를 작성해야한다.
sealed 클래스는 자체적으로 abstract 속성을 가진다. 그러므로 sealed 클래스는 직접 생성할 수 없다.
기본적으로 sealed class는 private 생성자를 가진다. sealed 클래스는 non-private 생성자를 가질 수 없다.
Enum class와 Sealed class는 유사하게 보인다.
enum 의 각 값들은 sealed class처럼 제한되어 사용된다.
차이점은 enum은 단지 단일 인스턴스만을 가지는 반면에, sealed class는 서브 클래스로 상속받으며 여러 인스턴스를 가질 수 있게 된다.
sealed class는 추상 클래스로 동작하며, 하나의 파일에 지정된 서브 클래스들을 하나로 묶어주는 역할을 한다.
그리고 이들을 이용하면 제한된 서브 클래스만을 사용하기 때문에 좀더 엄격한 클래스 관리를 할 수 있게 된다.
동일한 파일에 작성해야하므로, 특정 서브 클래스가 생성이 되면, 처리되어야하는 업무 역시 동일한 파일내에서 작성되도록 하면 생각하지 못한 오류를 방지할 수 있다.
from: https://www.programiz.com/kotlin-programming/sealed-class 에서 참조했다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.