Class
1 Class
1.1 클래스 정의
class Person(val name:String)
동일한 Java
public class Person{
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
1.2 프로퍼티
- 자바에서는 필드와 접근자를 한데 묶어 프로퍼티라고 합니다.
- 자바에서는 데이터를 필드에 저장하며 멤버 필드의 가시성을 일반적으로 private으로 정의합니다.
- 이 경우 클라이언트가 클래스의 필드에 접근이 필요한 경우 접근자 메서드를 사용합니다.
- 접근자 메서드는 getter와 setter가 있습니다.
- 코틀린은 프로퍼티를 언어 기본 기능으로 제공합니다.
- 코틀린의 프로퍼티는 자바의 필드와 접근자 메서드를 완전히 대신합니다.
- val로 선언한 프로퍼티는 읽기 전용입니다.
- 비공개 필드와 public getter를 만들어집니다.
- var로 선언한 프로퍼티는 읽기/쓰기가 가능합니다.
- 비공개 필드와 public setter와 getter를 만들어 냅니다.
1.3 커스텀 접근자
- 직사각형 클래스인 Rectangle을 정의하면서 자신이 정사각형인지 알려주는 기능을 만들어보자.
class Rectangle(val height:Int, val width:Int) {
val isSquare: Boolean
get () {
return height == width
}
}
- 정사각형인지를 별도의 필드에 저장할 필요가 없다.
- isSquare 프로퍼티에는 자체 값을 저장하는 필드가 필요없다.
- 이 프로퍼티에는 자체 구현을 제공하는 getter만 존재한다.
- 클라이언트가 프로퍼티에 접근할 때마다 getter가 프로퍼티 값을 매번 계산한다.
2 자바 클래스와 차이점
- 코틀린의 클래스는 기본적으로
final
,pulic
이다. - 중첩 클래스는 기본적으로 내부 클래스가 아니다.
- 외부 클래스에 대한 참조가 없다.
3 abstract class
- abstract로 선언한 클래스는 인스턴스화할 수 없다.
- 추상 멤버는 항상 열려있어 추상 멤버 앞에
open
변경자를 명시할 필요가 없다.
예시
- 추상 클래스에는 abstract 변경자를 붙인다.
- 추상 메서드에도 abstract 변경자를 붙인다.
- 메서드에 abstract 변경자를 붙이지 않으면 추상 메서드가 아니다.
abstract class Animated {
// 추상 메서드
abstract fun animate()
// 비추상 메서드도 기본적으로 final이기 때문에 원한다면 open을 명시해야 함
open fun stopAnimating() {}
// 비추상 메서드 기본적으로 final
fun animateTwice() {}
}
4 nested class
- 자바처럼 코틀린에서도 클래스 안에 클래스를 정의할 수 있습니다.
- 클래스 안에 다른 클래스를 선언하면 도우미 클래스를 캡슐화하거나 코드 정의를 그 코드 를 사용하는 곳 근처에 두는 데 유용합니다.
4.1 자바와의 차이점
- 자바의 nested class는 기본적으로 Inner Class로 선언됩니다.
- 자바의 Inner Class는
static
키워드 없이 선언된 중첩 클래스를 의미합니다. - Inner Class 클래스는 암묵적으로 바깥 클래스에 대한 참조를 가집니다.
- 자바에서 암묵적인 바깥 클래스에 대한 참조를 없애려면
static
키워드를 사용해야 합니다.
- 자바의 Inner Class는
- 코틀린에서는 nested class는 기본적으로 바깥 클래스에 대한 참조가 없습니다.
- 즉 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없습니다.
- 즉 자바의 Static Nested Class와 같습니다.
- 자바의 Inner Class처럼 바깥 클래스에 대한 참조 포함하고 싶다면
inner
변경자를 붙여야 합니다.
- 코틀린에서는 바깥 클래스의 인스턴스를 가리키는 참조를 표기하는 법이 자바와 다릅니다.
- 바깥쪽 클래스의 인스턴스에 접근하려면
this@Outer
라고 써야 합니다.
- 바깥쪽 클래스의 인스턴스에 접근하려면
4.2 내포 클래스와 내부 클래스
- 내포 클래스는 바깥 클래스에 대한 참조가 없는 중첩 클래스입니다.
class
키워드로 정의합니다.
- 내부 클래스는 바깥 클래스에 대한 참조가 있는 중첩 클래스입니다.
inner class
키워드로 정의합니다.
예시
class Outer {
inner class Inner {
fun getOuterReference() = this@Outer
}
}
- 내부 클래스 Inner에서 바깥 클래스 Outer의 인스턴스에 접근하려면
this@Outer
를 사용해야 합니다.
5 생성자와 초기화 블록
- 코틀린에서는 클래스의 인스턴스를 생성할 때 사용되는 두 가지 타입의 생성자가 있습니다.
- 주 생성자(primary constructor)와 부 생성자(secondary constructor).
- 이들은 클래스의 인스턴스화와 초기화 과정에서 중요한 역할을 합니다.
- constructor 키워드는 주 생성자나 부 생성자를 정의할 때 사용한다.
5.1 Primary Constructor(주 생성자)
- 클래스를 초기화할 때 주로 사용하는 생성자로 클래스 본문 밖에 정의합니다.
- 주 생성자는 생상자 파라미터를 지정하고 그 생성자 파라미터에 의해 초기화되는 프로퍼티를 정의하는 두 가지 목적으로 사용됩니다.
5.1.1 초기화 블록
- init 키워드는 초기화 블록을 시작할 수 있습니다.
- 초기화 블록에는 클래스의 객체가 만들어질 때 실행될 초기화 코드가 들어갑니다.
- 초기화 블록은 주로 주 생성자와 함께 사용됩니다.
- 주 생성자는 제한적이기 때문에 별도의 코드를 포함할 수 없어 초기화 블록이 필요합니다.
예시
class User constructor(_nickname: String) {
val nickname: String
init {
nickname = _nickname
}
}
- 위 예시에서 User 클래스는 nickname이라는 프로퍼티를 가지고 있습니다.
- nickname은 주 생성자 파라미터 _nickname으로 초기화됩니다.
class User(_nickname: String) {
val nickname: String = _nickname
}
- 위 예시를 더 간결하게 표현할 수 있습니다.
- 프로퍼티를 초기화하는 식이나 초기화 블록 안에서 주 생성자의 파라미터를 참조할 수 있습니다.
class User(val nickname: String)
- 위 예시를 더 간결하게 표현할 수 있습니다.
- 주 생성자의 파라미터로 프로퍼티를 초기화한다면 그 주 생성자 파라미터 이름 앞에 val을 추가하는 방식으로 프로퍼티 정의화 초기화를 간략히 위와 같이 쓸 수 있습니다.
- 생성자 파라미터에도 기본값을 지정할 수 있습니다.
5.2 Secondary Constructor(부 생성자)
- 부 생성자는 클래스 본문 안에 정의된 생성자입니다.
- 일반적으로 코틀린에서 생성자가 여럿 있는 경우가 많지 않습니다.
- 인자에 대한 기본값을 제공하기 위해 부 생성자를 사용하는 것은 권장되지 않습니다.
- 오버로드한 생성자가 필요한 경우 디폴트 파라미터 값과 이름 붙인 인자 문법을 사용해 해결할 수 있습니다.
- 부 생성자는
constructor
키워드로 정의합니다. - 클래스에 주 생성자가 없다면 모든 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에게 생성을 위임해야 합니다.
예시
class MyDownloader : Downloader {
constructor(url: String?) : this(URI(url))
constructor(uri: URI?) : super(uri)
}
- 첫 번째 부 생성자는 URI 객체를 만들어 다른 생성자에게 생성을 위임합니다.
- 두 번째 부 생성자는 super(uri)로 상위 클래스의 생성자를 호출합니다.
5.3 기반 클래스 생성자 호출
- 기반 클래스의 생성자가 인자를 받는 경우 클래스의 주 생성자에서 기반 클래스의 생성자를 호출해야 합니다.
- 기반 클래스를 초기화하려면 기반 클래스 이름 뒤에 생성자 인자를 괄호 안에 넣어야 합니다.