-
[코틀린] 객체와 클래스코틀린 2022. 3. 13. 00:49
1. 객체와 싱글톤
객체 표현식으로 사용하는 익명 객체
객체 표현식: object {} 형태로 구현하고 익명의 객체를 생성한다.
fun drawCircle() { val circle = object { val x = 10 val y = 20 val radius = 5 } println("Circle x: ${circle.x} y: ${circle.y} radius: ${circle.radius}")) } drawCircle() // Circle x: 10 y: 20 radius: 5
익명 객체는 인터페이스를 구현할 수도 있다. object: <인터페이스명> 으로 인터페이스를 구현하는 익명 객체를 만들 수 있다.
fun createRunnable(): Runnable { val runnable = object: Runnable { override fun run() { println("You called...") } } return runnable } createRunnable().run() //You called...
익명 객체가 Single abstract method interface(인터페이스 내에 추상 메소드가 1개일 경우) 이면 아래처럼 간단하게 구현할 수 있다. 오버라이드 하는 메소드의 이름을 따로 명시해주지 않아도 된다.
fun createRunnableSingle(): Runnable = Runnable { println("You called single method") } createRunnableSingle().run()
객체 선언을 이용한 싱글톤
object 와 {} 사이에 이름을 명시하면 익명 객체 생성을 위한 표현식이 아니라 싱글톤 객체를 선언하는 것이다.
object Util { fun numberOfProcessors() = Runtime.getRuntime().availableProcessors() } println(Util.numberOfProcessors()) // 프로세서 수 출력됨
싱글톤 객체 안에는 val, var를 사용할 수 있다.
싱글톤 객체가 상속받은 클래스나 인터페이스를 파라미터로 갖는 메소드에 인자로 넘길 수도 있다.
object Sun: Runnable { val radius = 696000 var temperature = 15000000 override fun run() { println("I`m Sun.") } } fun runSun(sun: Runnable) { sun.run() } runSun(Sun) // I`m Sun. 출력됨
2. 클래스 생성
클래스
코틀린 클래스는 아래처럼 간단하게 정의할 수 있다.
class Fruit // 가장 간단한 클래스 class Computer(val numberOfProcessor: Int, var color: String)
Computer 클래스의 괄호 안에는 val 로 선언된 Int형의 numberOfProcessor와 var로 선언된 String형의 color가 정의되어 있다. 코틀린은 자동적으로 생성자, 필드, getter를 정의해준다. val 로 선언된 필드는 객체 생성후 변경할 수 없다. var로 선언되 필드는 객체 생성 후에도 변경할 수 있다.
인스턴스 생성
코틀린에서 인스턴스를 만들때는 그냥 함수를 호출하듯이 하면 된다. new 키워드가 없다.
val computer = Computer(10, "Red") println("${computer.numberOfProcessor} ${computer.color}") // 10 Red
아래는 코틀린 컴파일러가 Computer.kt를 Computer.class로 컴파일한 코드의 일부다.
Compiled from "Computer.kt" public final class chapter07.Computer { private final int numberOfProcessor; private java.lang.String color; public chapter07.Computer(int, java.lang.String); public final int getNumberOfProcessor(); public final java.lang.String getColor(); public final void setColor(java.lang.String); }
변수들을 private으로 선언하고 val변수에 대해서는 getter를, var에 대해서는 getter와 setter를 정의해준다. 코틀린에서 computer.numberOfProcessor를 호출하면 실제로는 computer.getNumberOfProcessor를 호출한 것이다.
생성자에 제약을 두고 싶다면 아래와 같이 set으로 추가할 수 있다.
class ComputerWithSetter(val numberOfProcessor: Int, theColor: String) { var battery = 100 set(value) { println("set battery") field = if(value < 0) 0 else value } var color = theColor set(value: String) { println("set color ${value} ${field}") if(value.isEmpty()) { throw RuntimeException("value is Empty") } field = value } } computerWithSetter.color = "Blue" // set color Blue Black 출력 computerWithSetter.battery = 0 // set battery 출력
접근 제어자
코틀린에는 public, private, protected, internal 네 개의 접근 제어자가 있다.
- public: 기본 접근 제어자, 어디에서나 멤버를 조회할 수 있음
- private: 객체 내부에서만 접근 할 수 있음
- protected: 자식 클래스에서 접근하는 것을 허용함
- internal: 같은 모듈 내에서만 조회할 수 있음
class Computer(val numberOfProcessor: Int, var color: String) { public val publicA = 100 internal val internalA = 100 private val privateA = 100 protected val protectedA = 100 }
초기화 코드
기본적으로 코틀린 클래스는 클래스 파라미터를 파라미터로 하는 주 생성자를 갖는다. 여기에 init 블록을 정의해서 클래스를 초기화하는데 필요한 추가적인 작업을 할 수 있다.
class Person(_name: String, _age: Int) { var name = if(_name.isEmpty()) "Anonymous" else _name val age = _age init { if (_age < 10) { name = "junior: $name" } } }
init블록의 특징은 아래와 같다.
- 위에서부터 아래로 실행되며 속성과 파라미터를 사용할 수 있다.
- 여러개를 정의할 수 있다. 꼭 필요한 경우에만 사용하는 것이 좋다.
보조 생성자
모든 클래스는 아규먼트를 받지 않는 기본 생성자를 가지고 있다. 클래스 파라미터를 가지고 있으면 주 생성자도 함께 생성한다.
class Person(val name: String, val age: Int) { var location = "" var phone = "" constructor(name: String, age: Int, _phone: String): this(name, age) { phone = _phone } constructor(name: String, age: Int, _location: String, _phone: String): this(name, age, _phone) { location = _location } }
위와같이 기본으로 생성되는 생성자 외에 추가적으로 생성자를 만들 수도 있다. 이렇게 만든 보조 생성자는 다른 보조생성자나 주 생성자를 호출할 수도 있다.
3. 컴패니언 객체와 클래스 멤버
컴패니언 객체는 클래스 안에 정의한 싱글톤으로 클래스 레벨의 멤버들을 정의해둘 수 있다.
class ClassWithCompanion { companion object { var number: Int = 0 fun companionMethod() { println("Companion Method") } } fun printNumber() { println(number) } } val c1 = ClassWithCompanion() c1.printNumber() // 0 출력 ClassWithCompanion.number = 100 val c2 = ClassWithCompanion() c2.printNumber() // 100 출력 ClassWithCompanion.companionMethod() // Companion Method 출력
ClassWithCompanion 내에 정의된 companion 객체는 number와 companionMethod를 갖는다. 이 속성들은 ClassWithCompanion의 클래스 레벨에서 접근하여 사용할 수 있다.
컴패니언에 접근
컴패니언 객체를 직접 참조하고 싶으면 Companion 속성을 이용할 수도 있다.
val companionRef = ClassWithCompanion.Companion companionRef.companionMethod() // Companion Method 출력됨
컴패니언 객체에 이름을 지정해 줄 수도 있다.
class CompanionWithName { companion object AnonymousCompanion { fun getName(): String { return "Anonymous" } } } println(CompanionWithName.AnonymousCompanion.getName()) // Anonymous 출력
팩토리로 사용하는 컴패니언
컴패니언을 팩토리처럼 사용하면 클래스 생성 자체를 컴패니언에 맡길 수도 있다.
class Person private constructor(val name: String, val nation: String) { companion object PersonFactory { private const val KOREA = "KOR" fun createKorean(name: String): Person { if(name.isEmpty()) throw IllegalArgumentException("Give name") val p = Person(name, KOREA) return p } } } // Person("Kim", "KOR") 접근 불가능 val p = Person.createKorean("Park") println("${p.name} ${p.nation}") // Park KOR
주 생성자를 private constructor를 이용해 private로 만들고 companion object에 객체 생성을 위임했다.
4. 데이터 클래스
data class는 데이터를 관리하는데 사용하는 클래스다.
- 주 생성자에는 적어도 하나의 val이나 var가 필요하다. val, var가 없는 파라미터는 사용할 수 없다.
- equals, hashCode, toString, copy 메소드를 자동으로 만들어준다.
- componentN 메소드를 제공해준다
data class FootballPlayer(val name: String, val height: Int, val injured: Boolean) val kim = FootballPlayer("Kim", 180, false) println(kim) // FootballPlayer(name=Kim, height=180, injured=false) val injuredKim = kim.copy(injured=true) println(injuredKim) // FootballPlayer(name=Kim, height=180, injured=true) println(kim.component1()) // Kim
copy는 객체의 속성들을 shallow copy해서 새로운 객체를 만드는 메소드이다.
componentN메소드는 N 번째 속성을 가져오는데 구조분해에 활용된다.
val (nameOfKim, heightOfKim, _) = kim // kim 객체가 구조분해되어 각 변수에 할당됨 println("$nameOfKim $heightOfKim") // Kim 180 출력됨
'코틀린' 카테고리의 다른 글
[코틀린] 델리게이션 (0) 2022.03.16 [코틀린] 클래스와 상속 (0) 2022.03.13 [코틀린] 타입 안정성 (0) 2022.03.07 [코틀린] 컬렉션 (0) 2022.03.07 [코틀린] 외부 반복과 아규먼트 매칭 (0) 2022.03.07