728x90
프로퍼티의 접근 - Setter, Getter
- 자바의 필드 : 접근 메소드를 필요로 함
- 코틀린의 프로퍼티 : 변수 선언 외에 접근 메소드가 별도로 있음
- Getter/Setter : 코틀린의 프로퍼티 접근 메소드
class Person(var name: String, var age: Int) // 클래스 선언
fun main()
{
val user = User("Kim", 20)
val name = user.name //getter에 의한 프로퍼티 반환
user.age = 25 //setter에 의한 프로퍼티 값 변경
}
- 게터와 세터의 설정 원리 : 변수 설정 시 get(), set()이 각각 자동으로 선언됨
- 아래 양식처럼 암묵적으로 선언되며 같은 양식대로 직접 커스텀할 수 있음
Class bar(...)
{
val A : Int //불변형은 getter만 선언됨
get() = field
/*
프로퍼티를 get에 대입 시 무한 재귀 호출이 되기 때문에,
프로퍼티를 가리키는 변수인 field로 별도로 선언됨
*/
var B : Int //가변형은 get, set 모두 선언됨
get() = field
set(value)
{
field = value
}
}
지연 초기화
- 클래스의 프로퍼티는 null일 수 없으므로 객체 생성 시 초기화가 필요한데, 객체 정보가 나중에 나타나는 경우 나중에 초기화할 방법이 필요
- lateinit, lazy 키워드로 지연된 초기화 가능
- lateinit
- 클래스 간의 의존성이 있는 경우 (특정 클래스가 생성되어야 초기화할 수 있는 경우)
- 테스트를 위해 임시로 객체를 생성해야 하는 경우
- var형 프로퍼티만 가능
- 초기화 전에는 프로퍼티의 getter, setter 사용이 불가
class Person
{
lateinit var name : String
fun test()
{
if(~::name.isInitialized) println("not initialized") //초기화 여부 확인
else println("initialized")
}
}
fun main()
{
val kildong = Person()
kildong.test() //"not initialized"
kildong.name() = "Kildong" //isInitialized = true
kildong.test() //"initialized"
}
/////////////////////////////////////////////////////////
// lateinit을 이용한 클래스 생성의 지연 초기화
data class Person(var name : String, var age : Int)
lateinit var person1 : Person //클래스 지연 초기화
fun main()
{
person1 = Person("Kildong", 30) //생성자 호출 시점에 초기화
}
- lazy : 호출 시 by lazy로 지연 초기화
- val에서만 사용 가능, 초기화 후값 변경 불가
- lazy 키워드의 모드
- by lazy(mode = SYNCHRONIZED) : 단일 스레드의 사용 보장
- by lazy(mode = PUBLICATION) : 여러 곳에서 호출될 수 있으나 처음 초기화된 값 사용
- by lazy(mode = NONE) : 락이 되지 않으므로 여러 스레드의 접근이 가능하나 값이 일관되지 않을 수 있음
class Lazytest
{
init {println("init block")}
val subject by lazy
{
println("lazy init")
"kotlin programming"//subject 접근 시 대입됨
}
fun flow()
{
println("not init")
println("subject : $subject") // 이 시점에서 subject가 초기화됨
}
}
fun main()
{
val test = Lazytest()
test.flow()
}
- by를 이용한 위임
- 람다식을 사용
- 한 클래스가 다른 클래스에 위임
- 위임된 클래스 멤버는 참조 없이 호출
<var|val|class> 이름 : 자료형 by 위임자
- 위임을 쓰는 이유
- 코틀린 라이브러리는 open되지 않은 클래스(상속 불가)
- 표준 라이브러리의 복잡한 상속을 방지하나, 기능 확장이 어려움
- 위임 사용 시 : 클래스 기능에 추가 기능을 구현 가능
interface Animal()
{
fun eat() {...}
}
class Cat = Animal()
val cat = Cat()
class Robot = Animal by cat //Robot은 Cat의 멤버를 사용 가능
- 위임의 특수 키워드
- observable : 프로퍼티를 보다가 변경 발생 시 호출
- vetoable : 반환값에 따른 변경 허용 및 취소
import kotlin.properties.Delegates
class User
{
var name : String by Delegates.observable("NONAME")//observable 매개변수로 name 초기값 설정
{
prop, old, new -> //프로퍼티, 기존값, 새로운 값을 매개로 받음
println("$old->$new") //이벤트 발생(name값의 변화) 시 실행
}
}
정적 변수와 메서드
- 코틀린의 클래스는 동적으로 생성
- 동적 초기화 없이 사용 가능한 변수 = 정적 변수 : 코틀린에서는 컴패니언 객체라고 칭함
- 사용하지 않아도 메모리에 상주하므로 자주 사용하는 객체에 대해 사용
class Person
{
var id : Int = 0
var name : String = "kim"
companion object // 컴패니언 객체 : 객체 생성 없이 접근 가능
{
var lang : String = "Kor"
fun work()
{
println("working")
}
}
}
fun main()
{
println(Person.lang) //인스턴스 생성 없이 출력 가능
Person.lang = "Eng" //변경 가능
Person.work() //메소드 실행 가능
println(Person.name) //name은 companion이 아니므로 에러
}
728x90