티스토리 뷰

728x90

 

  1. 클래스 구조
class Person {
    var firstName: String = ""
    var familyName: String = ""
    var age: Int = 0

    fun fullName() = "$firstName $familyName"

    fun showMe() {
      println("${fullName()}: $age")
    }
}
 
  • 위 클래스의 인스턴스마다 firstName, familyName. age라는 프로퍼티와 fullName(), showMe()라는 함수가 포함된다.

 

cf) 파일명을 public 클래스의 이름과 동일하게 만들지 않아도 된다.

한 파일에 여러 public 클래스가 존재할 수 있다.

 

 

 

       2. 생성자

  • 주생성자
class Person(firstName: String, familyName: String) {
    val fullName = "$firstName $familyName"
   
    init {
      println("Created new Person instance: $fullName")
    }
}

fun main() {
    val person = Person("John", "Doe")
    println(person.fullName)
}
 
    • 주생성자 파라미터 
      • 클래스 헤더의 파라미터 목록.
      • 인스턴스 생성시 클래스의 파라미터에 전달된다.
      • 프로퍼티 초기화나 init 블록 내에서만 사용 가능하다.
      • 디폴트 값과 vararg를 사용할 수 있다.
    • init 블록
      • 주생성자가 호출될 때마다 수행되는 초기화 블록.
      • 블록 안에서 프로퍼티를 초기화할 수 있다.
      • 여러개 사용할 수 있고 return문이 들어갈 수 없다.
    • 주생성자 실행 후 모든 프로퍼티가 초기화되어야 한다.
    • 주생성자에 접근 제한자를 지정하기 위해서는 constructor 키워드를 명시해야 한다. 
      • ex) class Person protected constructor()

 

class Person(val firstName: String, val familyName: String) {
    val fullName = "$firstName $familyName" // 생성자 파라미터
   
    init {
      println("Created new Person instance: $fullName") // 생성자 파라미터
    }

    fun printFirstName() {
      println(firstName) // 멤버 프로퍼티
    }
}
    • 생성자 파라미터 → 멤버 프로퍼티
      • 생성자 파라미터 앞에 val/var 키워드를 붙이면, 생성자 파라미터와 이름이 같고 생성자 파라미터로부터 초기화되는 프로퍼티가 정의된다.
      • 프로퍼티 초기화나 init 블록에서 참조: 생성자 파라미터
      • 다른 위치에서 참조: 프로퍼티

 

class Person(val firstName: String, val familyName: String)
  • 이를 이용해 본문이 없는 클래스를 정의할 수 있다.

 

  • 부생성자
    • 인스턴스를 여러 방법으로 초기화하고 싶은 경우 사용할 수 있다.
    • constructor 키워드를 사용해서 선언한다.
    • 부생성자를 실행하기 전에 프로퍼티 초기화와 init 블록을 실행한다.
    • return을 사용할 수 있다.
    • 부생성자의 파라미터 목록에는 val/var 키워드를 사용할 수 없다. (내부에서는 불변 변수로 사용됨)

 

class Person {
    val fullName: String
    constructor(firstName: String, familyName: String):
        this("$firstName $familyName")
    constructor(fullName: String) {
        this.fullName = fullName
    }
}
    • 클래스에 주생성자가 없는 경우
      • 다른 부생성자를 위임하여 프로퍼티를 초기화할 수 있다.

 

class Person(val fullName: String) {
    constructor(firstName: String, familyName: String):
        this("$firstName $familyName")
}
    • 클래스에 주생성자가 있는 경우
      • 모든 부생성자는 주생성자에게 위임 하거나 다른 부생성자에게 위임해야 한다.

 

 

 

       3. 내포된 클래스 (nested class)

  • 클래스 내부에서 다른 클래스를 정의할 수 있다.
class Person(private val id: Id) {
    class Id(private val name: String) {
      fun nameSake(person: Person) = person.id.name == name // 가능
    }
   
    fun showMe() = println("${id.name}") // error
}
 
  • 바깥쪽 클래스에서 내포된 클래스의 private 멤버에 접근할 수 없다.
  • 클래스 밖에서는 바깥쪽 클래스명.내포된 클래스명 으로 사용한다. 
    • ex) Person.Id("John")

 

  • 내부 클래스 (inner class)
class Person(val firstName: String, val familyName: String) {
    inner class Possession(val description: String) {
        fun showOwner() = println(fullName()) // println(this@Person.fullName())
    }
     
    fun fullName() = "$firstName $familyName"
}

fun main() {
    val person = Person("John", "Doe")
    val wallet = person.Possession("Wallet")
    wallet.showOwner()
}
    • 내포된 클래스에 inner를 붙이면 바깥쪽 클래스의 인스턴스에 접근할 수 있다.
    • 클래스 밖에서는 바깥쪽 클래스명이 아닌 인스턴스명.내부 클래스명 으로 사용한다.
    • 내부 클래스 내에서 외부 클래스의 인스턴스를 가리켜야 한다면 this@외부 클래스명 으로 사용한다.
      • ex) this@Person 
      • 읿반적으로 this는 항상 가장 내부 클래스의 인스턴스를 가리킨다.

 

 

 

       4. 지역 클래스

fun main() {
    var x = 1

    class Counter {
      fun increment() {
          x++
      }
    }

    Counter().increment()
    println(x) // 2
}
 
  • 함수 내에서 클래스를 정의할 수 있다.
  • 지역 클래스는 자신을 둘러싼 코드 블록 안에서만 쓰일 수 있다. (→ 접근 제한자를 붙일 수 없다.)
  • 자신을 둘러싼 코드 블록의 값을 접근하고 변경할 수 있다.
  • 지역 클래스의 내포된 클래스는 항상 inner 클래스여야 한다. 

 

 

       5. nested class ↔ inner class 

  • nested class
    • 외부 클래스와 독립적으로 존재한다. 외부 클래스의 인스턴스와 관련이 없다.
    • 외부 클래스의 멤버에 접근할 수 없다.
    • 해당 클래스의 인스턴스를 생성할 때 메모리에 독립적인 공간이 할당된다. 

 

  • inner class
    • 외부 클래스의 인스턴스와 연관되어 있다.
    • 외부 클래스의 멤버 함수나 프로퍼티에 접근할 수 있다.
    • 외부 클래스의 인스턴스가 생성되어야만 inner class의 인스턴스를 생성할 수 있다.
    •  inner class의 인스턴스는 외부 클래스의 인스턴스와 연결된 메모리 주소를 가진다. (외부 클래스의 참조를 가짐)
      • 외부 클래스가 삭제되더라도 inner class가 남아있다면 메모리 누수가 발생할 수 있다.

 

  • 지역 클래스 내에서 nested class는 선언할 수 없고 inner class만 가능한 이유
    • 지역 클래스는 자신을 둘러싼 불록의 값에 접근하거나 값을 변경할 수 있다.
    • nested class는 외부 클래스의 값에 접근할 수 없는데, 지역 클래스 안에서는 접근이 가능하다면 가시성 규칙에 어긋난다.

 

 

728x90
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함