코틀린 프로퍼티(kotlin property)
24 May 2019 | lambda 프로퍼티 접근자코틀린은 프로퍼티를 언어 기본 기능으로 제공한다. 프로퍼티란 무엇일까? 프로퍼티란 필드와 접근자를 통칭하는 것이다. 일반적인 자바빈 클래스인 Person을 보면서 정확히 알아보자.
public class Person {
private final String name;
private boolean isMarried;
public Person(String name, boolean isMarried) {
this.name = name;
this.isMarried = isMarried;
}
public String getName() {
return this.name;
}
public void setIsMarried(boolean isMarried) {
this.isMarried = isMarried;
}
public boolean getIsMarried() {
return this.isMarried;
}
}
자바에서는 데이터를 필드(field)에 저장한다. name
과 isMarried
라는 데이터를 Person클래스의 필드에 저장한 것이다. 한편 각 데이터마다 적용되는 getter와 setter를 접근자라 부른다. 이 접근자를 통해서 가시성이 private인 데이터들에 접근할 수 있다.
위의 자바 코드에서 Person클래스 필드에 들어가는 데이터들이 점점 증가한다면 getter와 setter같은 보일러플레이트 코드가 지저분하게 많아진다. 코틀린에서는 위의 Person클래스를 간단하게 정의할 수 있다.
class Person(val name: String, var isMarried: Boolean)
이 한줄의 코틀린 코드는 21줄의 자바 코드와 완전히 동일한 코드다.
자세히보면 자바코드에서 setter를 제공하지 않는 name
은 val
로 선언하였고, getter와 setter모두 제공하는(조회화 변경을 모두 허용하는) isMarried
는 var로 선언했다. 익히 알고있듯이 val은 불변, var은 가변 데이터를 선언할 때 사용한다. 이와 같은 맥락으로 val로 선언한 name
은 setter가 생성되지 않는다. 이 부분을 코드로 보자면 아래와 같다.
class Person {
val name: Int
get() {
return this.age
}
var isMarried: Boolean
get() {
return this.isMarried
}
set(isMarried: Boolean) {
this.isMarried = isMarried
}
}
val
로 선언한 name의 경우 setter가 없다. setter를 만들고 싶어도 val은 불변이기에 만들 수 없다(억지로 만드려고 하면 컴파일에러가 뜬다). 참고로 위에서 get()
과 set()
을 정해준 것은 커스텀 접근자이다. 기본적으로는 코틀린 클래스를 만들 때 생성자에 넣어준 데이터들에 대하여 get()과 set()이 숨겨져 있으나, 위의 코드처럼 명시적으로 적어줄 수 있다. 그말은 getter와 setter를 커스텀 할 수도 있다는 뜻이다.
생성자에 val, var의 유무 차이
class Person(val name: String) // 1
class Person(name: String) //2
이 둘의 차이는 무엇일까? 먼저 생성자에 val(또는 var)이 있는 경우 멤버변수로 변환된다. 즉 class Person(val name: String)
의 경우 아래 자바 코드로 변환된다.
public final class Person {
@NotNull
private final String name;
@NotNull
public final String getName() {
return this.name;
}
public Person(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
}
}
반면 class Person(name: String)
의 경우 아래의 자바 코드와 같다.
public final class Person {
public Person(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
}
}
코틀린 클래스 생성자에 val
이나 var
이 없는 경우에는 주 생성자의 파라미터들은 딱 생성자(init {...}
) 또는 프로퍼티를 초기화 하는 식에서만 사용 가능하다. 따라서 클래스의 생성자 외 다른 메서드에서는 사용할 수 없다(프로퍼티가 되지 못했기 때문).
class Person(name: String) {
init {
println(name)
}
}
위 코드는 아래의 자바 코드로 변환된다.
public final class Person {
public Person(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
System.out.println(name);
}
}
주의할 점
디컴파일한 자바 코드에서 필드가 private이라고 하여 코틀린의 프로퍼티도 private은 아니다. 이게 무슨말인가 싶겠지만, 필드와 프로퍼티를 다르게 인식할 줄 알아야 한다. 자바는 기본적으로 필드로 다루고, 코틀린은 프로퍼티(필드 + 접근자)를 기본으로 다루는 언어다.
class Person(var name: String)
위의 코드는 아래의 자바코드가 된다.
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public Void setName(String value) {
this.name = value;
}
public String getName() {
return this.name;
}
}
자바 필드인 name
자체만 보면 private 키워드가 붙어있으므로 private이 맞지만, 프로퍼티 전체를 보면 다르다. 필드는 private이지만 getter와 setter로 접근이 모두 가능하기 때문에 프로퍼티는 private하다고 볼 수 없다. 위의 코드에서 name
프로퍼티가 private이기 위해서는 아래와 같은 코틀린 코드가 필요하다.
class Person(private var name: String)
name 앞에 private
이 붙었다. private
이 붙지 않은 상태였어도 디컴파일한 자바 코드의 필드에는 private
이 붙지만, 코틀린은 기본적으로 필드가 아닌 프로퍼티를 다루기 때문에 프로퍼티 전체가 private
이 된다. 디컴파일된 자바 코드는 아래와 같다.
public final class Property {
private String name;
public Property(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
}
}
getter와 setter가 없어서 프로퍼티가 private이라고 볼 수 있다.
핵심
- 자바는 필드를 기본으로, 코틀린은 프로퍼티를 기본으로 다룬다.
- 디컴파일된 자바 코드의 필드가 private이라고해서 kotlin 프로퍼티가 private인 것은 아니다.
Comments