매일 한줄 코딩

#8. 코틀린 프로퍼티와 필드 (Properties and Fields) 본문

develop/kotlin

#8. 코틀린 프로퍼티와 필드 (Properties and Fields)

ShipJH 2022. 6. 6. 23:28
8. Properties and Fields

8. Properties and Fields


1. 프로퍼티 선언

자바에서는 프로퍼티를 지원하지 않음 ( getter, setter ) 그래서 lombok을 이용하였다.

코틀린에서는 기본으로 지원해준다.

  • 프로퍼티 선언시 구분
    • var (mutable)
    • val (read-only)
  • 프로퍼티 사용은 자바의 필드를 사용하듯 하면 된다.
class Member {
	var nickName: String = "SHIPJH"
	val name: String = "BAE JAE HYUN"
} // 프로퍼티인지, 필드(멤버변수)인지, 뭔지 알기 힘들다.....

fun copyName(member: Member): Member {
	val customer = MEmber()
	customer.name = member.name
	//...
	return customer
}

프로퍼티인지, 필드(멤버변수)인지, 뭔지 알기 힘들다.....

1-1. 프로퍼티 문법

  • 전체문법
var <propertyName>[: <PropertyType>] [=<property_initializer>]
	[<getter>]
	[<setter>]

  • 옵션 (생략가능 [ ]부분 )
    • PropertyType
      • property_initializer에서 타입을 추론 가능한 경우 생략가능
    • property_initializer
    • getter
    • setter

생략이 가능하기 때문에, 프로퍼티인지 필드인지 구분하기 조금 어렵다.

fun main(args: Array<String>) {
	var obj = Member()
	println(obj.name) // JAE HYUN
	// 디컴파일하여 본다면, getter가 생성되있는것을 볼 수 있다.
}

class Member {
	var name: String = "JAE HYUN"
}

코틀린은 캡슐화에 특화되있다.!

1-2. 프로퍼티 getter setter 재정의.

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

    obj.name = "_JH"
    println(obj.name)
}

class Member {
    var name: String = "JAE HYUN"
        get() { return "BAE $field" } // field 는 this.name이라 생각하면됨.
        set(value) { field = value}   // value는 받는 인자파라미터라고 생각하면 됨.
}
/*
BAE JAE HYUN
BAE _JH
*/

1-3. var (mutable) 프로퍼티

class Member {
	// default로 getter setter가 생김
	// 타입은 Int
	var initialValue = 1

	// error 발생
	// default로 getter와 setter에 명시적인 초기화를 해주어야 한다.
	var initialValue1: Int?
}

1-4. val (read-only) 프로퍼티

val은 read-only 이기 때문에 값을 재정의할 수 없다. 때문에 setter가 없다.

class Member {
	// default로 getter setter가 생김
	// 타입은 Int
	val initialValue = 1

	// error 발생
	// default로 getter에 경우 명시적인 초기화를 해주어야 한다.
	val initialValue1: Int?
}

1-5. 프로퍼티 접근제한자(가시성)

var name: String = "BAE"
	private set // body없이 작성해도 된다. private 이기 때문에.

var name2: Any? = null
	@Inject set // 어노테이션도 마찬가지.


2. Fields

2-1. Backing Fields

  • 코틀린 클래스는 field를 가질 수 없다.
  • field 라는 식별자를 통해 접근할 수 있는 automatic backing filed를 제공한다.
  • filed는 프로퍼티의 accessor 에서만 사용가능하다.
var count = 0
	set(value) {
		if (value >= 0) field = value
	}

2-2. Backing Fileds 생성 조건

  • accessor(getter, setter) 중 1개라도 기본 구현을 사용하는 경우
  • accessor(getter, setter) 재정의하여 filed 식별자를 참조하는 경우.
var count = 0
	set(value) {
		if (value >= 0) field = value
	}

  • 아래의 경우는 Backing Fileds 를 생성하지 않음
val isEmpty: Boolean
	get() = this.size == 0

2-3. Backing Properties 생성 방법

backing field 방식이 맞지 않는 경우에는 Backing Properties를 이용할 수도 있다.

private var _table: Map<String, Int>? = null
public val table: MAp<String, Int>
	get() {
		if (_table == null) {
			_table = HashMap()
		}
		return _table ?: throw Exception(....)
	}

2-4. const ( Compile-Time Constants ) 생성 조건

  • 상수의 개념이며, 어노테이션에서도 사용이 가능하다.
  • 조건
    • Top - level
    • String이나 프리미티브 타입으로 초기화된 경우에 사용가능
const val STRING_DASH: String = "-"

@Deprecated(STRING_DASH)
fun foo() {...}

2-5. Late-Initialized Properties

  • 일반적으로 프로퍼티는 non-null 타입으로 선언이된다.

    하지만, 간혹 non-null타입 프로퍼티를 사용하고 싶지만, 생성자에서 초기화를 해줄 수 없는 경우가 생긴다

    • Dependency injection
    • Butter knife ( view 부분 사용할때.. 미리 값을 할당하지 않을때. )
    • Unit test의 setup 메소드
public class MyTest {
	// 실제로 컴파일하려면 ?를 써서 nullalbe을 써서 null로 초기화 해야된다. 
	// 그렇게 되면 모든곳에서 null체크를 해야됨..
	lateinit var subject: TestSubject 


	// 때문에 setup에서 값할당.
	@Setup fun setup() {
		subject = TestSubject()
	}

	@Test fun test() {
		subject.method()
	}
}

lateinit 를 사용하여 나중에 할당한다는것 알려주면 된다.

  • 사용 조건
    • 클래스의 바디에서 선언된 프로퍼티만 가능
    • 기본생성자에서 선언된 프로퍼티는 안됨
    • var 프로퍼티만 가능
    • non-null 타입이어야 함
    • 프리미티브 타입이면 안됨
    • lateinit 프로퍼티가 초기화 되기 전에 접근하면 오류발생
    • custom accessor(getter, setter 재정의) 가 있으면 안됨.
class  Member {
	lateinit var name: String // 클래스 바디에 선언되어야 함

	fun setUp() {
		name = "late"
	} // name에 lateinit을 안써주면 에러가 발생함. 이닛블록이 아니여서.
}


class  Member2(lateinit var name: String ) { // 생성자에 선언된 프로퍼티 안됨
	//...
}


class  Member3 {
	lateinit val name: String // val은 안됨. var만 가능
	//...
}


class  Member4 {
	lateinit var name: String 
		gert() {return field} // custom accessor(getter, setter 재정의) 가 있으면 안됨.
	...
}

class  Member5 {
	lateinit val name: Int // 프리미티브 타입이면 안됨
	//...
}

class  Member6 {
	lateinit val name: String? // nullable은 안됨. non-null 타입이어야함.
	//...
}

Comments