[Kotlin] 6. 프로퍼티와 초기화
※ “Do it! 코틀린 프로그래밍” 을 참고하여 작성하였습니다.
06-1 프로퍼티의 접근
코틀린에서 게터와 세터가 작동하는 방식
- class 클래스 이름(val a: Int, var b: Int): 클래스 이름 뒤에 프로퍼티를 설정
- 클래스로 객체를 생성한 다음, .(점)으로 프로퍼티에 접근
- ex: user.name, user.age
기본 게터와 세터 직접 지정하기
var은 get, set 모두 가능 / val은 get만 가능
var 예시
1 2 3 4 5
var name: String= _name get()= field set(value){ field= value }
val 예시
1 2
val id: Int= _id get()= field
field(보조 필드): 프로퍼티를 참조하는 변수
value: 세터의 매개변수로 외부로부터 값을 가져옴
→ value는 다른 문자열이어도 됨
커스텀 게터와 세터의 사용
커스텀 게터와 세터: 사용자가 직접 게터와 세터를 정의하면서 새로운 내용을 작성하는 것
보조 프로퍼티의 사용
- 보조 필드를 사용하지 않는 경우,
- 임시적으로 사용할 프로퍼티를 선언해놓고 게터나 세터에서 사용할 수 있음
프로퍼티의 오버라이딩
상위 클래스로부터 상속받은 하위 클래스에서 게터와 세터를 재정의할 수 있음
→ 단, 상위 클래스 앞에 open 키워드 필수
06-2 지연 초기화와 위임
lateinit을 사용한 지연 초기화
- lateinit의 제한
- var로 선언한 프로퍼티만 가능
- 프로퍼티에 대한 게터와 세터를 사용할 수 없음
- 프로퍼티 초기화 여부 확인
- ::프로퍼티.isInitialized
[객체 지연 초기화하기]
- 함수 밖에 lateinit 키워드로 생성자의 값 할당 없이 객체를 먼저 생성하고,
- main() 에서 생성자와 함께 객체를 초기화
- lateinit의 제한
lazy를 사용한 지연 초기화
- lazy의 특징
- 호출 시점에 by lazy {…} 의 정의에 의해 블록 부분의 초기화를 진행
- 불변 변수인 val(읽기 전용)에서만 사용 가능
- val이므로 값을 다시 변경할 수 없음
[객체 지연 초기화하기]
by lazy: person 객체의 지연 초기화
1 2 3 4 5 6 7 8
class Person(val name: String, val age: Int) fun main(){ val person: Person by lazy{ Person("Kim", 23) } println("person.name= ${person.name}") // 이 때 초기화, person.name= Kim }
lazy: 변수에 lazy 객체가 위임되므로, 객체에 접근(초기화)할 때 .value를 한 번 더 써주어야 함
1 2 3 4 5 6
class Person(val name: String, val age: Int) fun main(){ val personDelegate= lazy { Person("Hong", 40) } println("personDelegate.value.name= ${personDelegate.value.name}") }
- lazy의 특징
lazy 모드(아리까리 하다.. 초기화의 접근 범위에 따라 달라지는건지?)
- SYNCHRONIZED: lock을 사용해 단일 스레드 만이 사용하는 것을 보장(default)
- PUBLICATION: 여러 군데에서 호출될 수 있으나 처음 초기화된 후 반환값을 사용
- NONE: lock을 사용하지 않기 때문에 빠르지만, 다중 스레드가 접근할 수 있음
by를 이용한 위임
클래스 위임
[형식] class 클래스 이름: 자료형 by 위임자
- 위임된 클래스의 메소드는 정적 메소드로 생성됨
- 즉, 위임된 클래스의 메소드나 프로퍼티를 활용할 수 있음
프로퍼티 위임
[형식] (var or val) 프로퍼티: 자료형 by 위임자
observable() 함수의 위임
프로퍼티 값이 변경되는지 감시
1 2 3 4 5 6 7 8
import kotlin.properties.Delegates class User{ var name: String by Delegates.observable("NONAME"){ prop, old, new -> println("$old -> $new" } }
vetoable() 함수의 위임
Boolean 값이 나오도록 조건을 설정해서, 조건이 맞지 않으면 값 할당을 거부
1 2 3 4 5 6 7 8 9
import kotlin.properties.Delegates fun main(){ var max: Int by Delegates.vetoable(0){ prop, old, new -> new > old // 조건에 맞지 않으면 거부권 행사 } ... }
06-3 정적 변수와 컴패니언 객체
: 프로그램을 실행할 때 고정적으로 가지는 메모리로 객체 생성 없이 사용할 수 있음
컴패니언 객체
Explanation
- 실제 객체의 싱글톤으로 정의
- 객체가 서로 동일한 정보를 가질 때 하나의 메모리만 유지해 자원의 낭비를 줄일 수 있음
예시
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class Person{ var id: Int= 0 companion object{ var language: String= "Korean" fun work(){ println("working. . .") } } } fun main(){ println(Person.language) // Korean Person.work() // working. . . }
코틀린에서 자바의 static 멤버 사용하기
- 클래스명.프로퍼티
- 클래스명.함수()
자바에서 코틀린 컴패니언 객체 사용하기
[코틀린]
- const val 프로퍼티= “hi~”
- @JvmStatic fun 함수()= println(”hi~”)
- @JvmField val 프로퍼티= 클래스()
[자바]
- 애노테이션 사용: 클래스.함수()
- 애노테이션 사용X: 클래스.Companion.함수()
최상위 함수
or 패키지 레벨 함수: 클래스없는 함수
자바에서 최상위 함수 접근하기
클래스Kt.최상위 함수()
@file:JvmName(”PKLevel”)
PKLevel.최상위 함수()
object 클래스: 선언과 동시에 객체 생성
- 예시: object OCustomer{ … }
- 생성자 선언 X
- 자바에서 object로의 접근: 클래스.INSTANCE.함수()
object 표현식: 하위 클래스를 만들지 않고 오버라이딩
1 2 3 4 5 6 7 8 9
open class Superman(){ open fun fly()= println("Flying in the air.") } fun main(){ val pretendedMan= object: Superman(){ override fun fly= println("I'm not a superman. I can't fly!") } }
활용 예시
1 2 3 4 5 6 7 8 9
interfact Shape{ fun onDraw() } val triangle= object: Shape{ // 상위 인터페이스를 한번 객체로 써서 오버라이딩 override fun onDraw(){ ... } }
1 2 3 4 5 6 7
fun foo(){ // 객체(adHoc)는 필요하지만 상위 인터페이스나 클래스가 없는 경우 val adHoc= object{ var x: Int= 0 var y: Int= 0 } println(adHoc.x + adHoc.y) }