[Kotlin] Properties and Fields

래림·2022년 11월 17일

Kotlin

목록 보기
1/3

프로퍼티 선언

코틀린 클래스는 프로퍼티를 가질 수 있다.

var은 mutable, val 은 read-only

class Address{
	var name:String = "Kotlin"
    var city:String = "Seoul"
}

프로퍼티 사용은 자바의 필드를 사용하듯이 하면 된다.

fun copyAddress(address:Address) : Address{
	val result = Address()
    result.name=address.name
	...
	return result	
}

그렇다는데 솔직히 아직 난 자바랑 무슨차인지 모르겠다.

프로퍼티란?

프로퍼티란 자바필드의 변수적인 부분과, getter,settet의 함수적인 부분이 포함된 것이다. 뭔소리?????
예시를 보면서 이해를 해봅시다.

다음과 같은 코틀린 코드를

fun main(args:Array<String>){
    var obj=Address()
    println(obj.name)
}

class Address{
    val name:String = "Kotlin" //프로퍼티
}

자바코드로 바꾼다면 다음과 같다.

public final class Other2Kt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkNotNullParameter(args, "args");
      Address obj = new Address();
      String var2 = obj.getName();
      System.out.println(var2);
   }
}



public final class Address {
   @NotNull
   private final String name = "Kotlin";

   @NotNull
   public final String getName() {
      return this.name;
   }
}

java코드를 보면, private로 선언된 변수 name을 getName()이라는 함수를 통해 읽는다는것을 알 수 있다.
getter 와 setter를 프로그래밍 언어 수준에서 제공한다고 생각하면 될듯!!

프로퍼티 문법

-전체문법

var <propertyName>[: <PropertyType>] [=<property_initializer>]
[<getter>]
[<setter>]

외부적으로 볼 땐, name이라는 필드에 바로 접근한 것처럼 보이지만
사실은 getter라는 accessor를 통해 접근한 것이다.

Custom accessors (getter, setter)

custom accessor는 프로퍼티 선언 내부에, 일반 함ㅁ수처럼 선언할 수 있다.
//관습적으로 setter의 파라미터 이름은 value이다. 변경 가능!!

  • getter
val isEmpty:Boolean
	get() = this.size==0
  • setter
var stringRepresentation : String
	get() = this.toString()
    set(value){
    setDataFromString(value)
    }

기본 accessor의 수정없이 body없는 accessor를 통해 정의 가능하다.

accessor에 visibility 변경이 필요하거나
accessor에 annotation이 필요한 경우
(accessor인데 visibility를 변경할 이유가 뭐지? 무조건 열려있어야 하는거 아닌가? 이건 더생각해봐야할듯
강의에서는 setter를 private으로 설정할 경우라는데, 음? 그럼 val로 변수를 만들어서 set 못하게 하면 되는거 아닌감?)

var setterVisibility: String = "abc"
	private set
var setterWithAnnotation: Any? = null
	@Inject set //annotate the setter with Inject

body를 작성해주어도 된다.

var setterVisibility:String = "abc"
	private set(value){
	field = value
}

Backing Fields

코틀린 클래스는 field를 가질 수 없다.
field라는 예약어를 통해 접근할 수 있는, automatic backing field를 제공한다. field는 프로퍼티의 accessor에서만 사용 가능하다.

var counter = 0
	set(value){
    	if(value >= 0) field = value
    }

Backing Fields 생성조건

  • accessor 중 1개라도 기본구현을 사용하는 경우
  • custom accessor에서 field 식별자를 참조하는 경우
var counter = 0 
	set(value){
    	if(value >= 0)field = value
    }
  • 아래의 경우에는 backing field가 생성되지 않는다.
    val이라서 set이 없다.set에서 field를 사용하지 않았기 때문에 backing field가 생성되지 않는다.
val isEmpty : Boolean
	get() = this.size == 0

Backing Field가 안생기는 경우


fun main(args:Array<String>){
    var obj=Address()
    println(obj.isEmpty)
}
class Address{
    val isEmpty : Boolean
        get(){return isEmpty}

}
public final class Address {
   public final boolean isEmpty() {
      return this.isEmpty();
   }
}

Backing Field가 생기는 경우


fun main(args:Array<String>){
    var obj=Address()
    println(obj.isEmpty)
}
class Address{
    val isEmpty : Boolean = false
        get(){return field}

}
public final class Address {
   private final boolean isEmpty;

   public final boolean isEmpty() {
      return this.isEmpty;
   }
}

Compile-Time Constants

  • const modifier를 이용하면 컴파일 타임 상수를 만들 수 있다.
    -이런 프로퍼티는 어노테이션에서도 사용 가능하다.
  • 조건 : Top-level인 경우, object의 멤버인 경우, String이나 primitive type으로 초기화 된 경우

const val MY_CONST = "CONST" // 이렇게 topLevel이어야 한다.

@Deprecated(MY_CONST)
fun main(args:Array<String>){
    var obj=Address()
    println(obj.isEmpty)
}
class Address{
    val isEmpty : Boolean
        get(){return isEmpty}

}

Late-Initialized Properties

  • 일반적으로 프로퍼티는 non-null type으로 선언된다.
  • 그러나 non-null type 프로퍼티를 사용하고 싶지만, 생성자에서 초기화 해줄 수 없는 경우가 있다.
    (Dependency injection, Unit test의 setup 메소드)
    이걸 사용 안하고 초기화를 나중에 해주려면, 프로퍼티 선언 시 nullable? 을 모두 써줘야 한다. 그리고 해당되는 모든 코드에도..마찬가지로.. (swift쓸때도 비슷한 상황이 있었던거 같다.)

조건

fun main(args:Array<String>){
    var obj=Address()
    println(obj.data)
}
class Address{
    var data : String
    init{
        data="Kotlin"
    }

}

테스트 때문에 init이 아니라 setUp() 함수에서 초기화를 해야하는 경우 이렇게 해야한다.


fun main(args:Array<String>){
    var obj=Address()
    println(obj.data)
}
class Address{
   lateinit var data : String
   fun setUp(){
       data="나중에"
   }

}














참고한 강의영상

0개의 댓글