프로퍼티란 필드와 접근자를 통칭하는 것입니다.
이렇게 말하면 이해하기가 힘들기 때문에 일반적인 자바 클래스인 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;
}
}
자바에서는 데이터를 필드에 저장합니다. name과 isMarried라는 데이터를 Person 클래스의 필드에 저장한 것입니다. 한편 각 데이터마다 적용되는 getter와 setter를 접근자라 부른다. 이 접근자를 통해서 가시성이 private인 데이터들에 접근할 수있습니다.
필드(field) : 클래스의 속성값을 저장하기 위해 선언하는 변수들을 필드라고 합니다. 필드는 다른 말로 멤버변수나 전역변수라고 합니다.
필드는 클래스 안에서 선언 위치에 따라 3가지로 구분됩니다.
메서드 안에 선언된 변수를 의미합니다. 메서드가 호출될 때 생성되고 메서드가 종료될 때 삭제됩니다. stack 메모리에 저장되며 접근 지정자를 사용할 수 없습니다. 기본적으로 변수가 존재하는 블록에서만 사용할 수 있기 때문에 블록변수라고도 합니다. 반드시 사용하기 전에 초기화해야합니다.
(멤버 변수 : 인스턴스 변수, 클래스 변수 -> 선언 위치가 클래스 영역)
메서드 밖에서 선언된 변수 중 static 키워드를 사용하지 않고 선언된 변수입니다. 인스턴스(객체)가 생성될 때 생성되며 객체가 삭제될 때 삭제됩니다. 인스턴스 별로 다른 값을 가질 수 있으므로, 각각의 인스턴스마다 고유의 값을 가져야할 때는 인스턴스 변수로 선언합니다. heap 메모리에 저장되며 각 객체의 정보를 저장하는데 사용되어 멤버 변수라고도 합니다.
클래스 변수는 메서드 밖에서 선언된 변수 중 static 키워드를 사용하여 선언한 변수입니다. 프로그램이 실행될 때 생성되고 프로그램이 종료될 때 삭제됩니다. 단 한 번만 생성되고 객체 생성 없이 클래스명.변수명으로 접근할 수 있습니다. 메서드 영역에 할당되고 객체(인스턴스) 간에 공유되기 때문에 공유변수라고도 합니다.
다시 돌아와 위의 코드를 보면 Person클래스 필드에 들어가는 데이터들이 점점 증가한다면 getter와 setter같은 보일러 플레이트 코드가 지저분하게 많아집니다. 코틀린에서는 위의 코드를 확연하게 줄여줍니다.
class Person(val name: String, var isMarried:Boolean)
이 한줄로 위의 자바 코드를 대체할 수 있습니다.
setter를 제공하지 않는 name은 val로 선언하고 getter와 setter를 모두 제공하는 isMarried는 var로 선언하였습니다.
val은 불면, var은 가변이라고 생각하시면 됩니다.
프로퍼티는 일반 변수처럼 보이지만 함수가 내장된 변수입니다. 접근자로 불리는 함수가 내장되어 있습니다. 코틀린에서는 필드 뿐만 아니라 접근자 메서드도 자동으로 생성해줍니다. property는 사용은 필드처럼 하지만 호출하게 되면 함수처럼 호출됩니다.
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
initializer, getter, setter 는 optional 입니다. initializer 로부터 타입을 추론하는 것이 가능하다면 프로퍼티의 타입을 생략하는것이 가능합니다.
var counter = 0 // the initializer assigns the backing field directly
get() = field
set(value) {
if (value >= 0)
field = value
// counter = value // ERROR StackOverflow: Using actual name 'counter' would make setter recursive
}
프로퍼티는 get(), set() 함수를 가지고 있고 프로퍼티가 가진 값은 field에 저장되어 있습니다. get(),set()으로 데이터를 읽기 및 수정을 할 수 있습니다.
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 {...}) 또는 프로퍼티를 초기화 하는 식에서만 사용 가능합니다.