Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Value too long for column
- 자원부족
- mp4fpsmod
- PersistenceContext
- preemption #
- pytest
- python
- taint
- 헥사고날아키텍처 #육각형아키텍처 #유스케이스
- JanusWebRTC
- JanusWebRTCGateway
- 달인막창
- 오블완
- PytestPluginManager
- 겨울 부산
- JanusGateway
- 티스토리챌린지
- tolerated
- VARCHAR (1)
- kotlin
- JanusWebRTCServer
- table not found
- terminal
- vfr video
- Spring Batch
- 깡돼후
- 코루틴 빌더
- k8s #kubernetes #쿠버네티스
- 코루틴 컨텍스트
- 개성국밥
Archives
너와 나의 스토리
[Kotlin] 클래스와 인터페이스1 - 초기화(주 생성자와 부 생성자)/가시성 변경자/프로퍼티 본문
Programming Language/Kotlin
[Kotlin] 클래스와 인터페이스1 - 초기화(주 생성자와 부 생성자)/가시성 변경자/프로퍼티
노는게제일좋아! 2021. 6. 14. 10:19반응형
코틀린의 클래스와 인터페이스는 자바 클래스, 인터페이스와는 약간 다르다.
- 인터페이스에 프로퍼티 선언이 들어갈 수 있다.
- 코틀린 선언은 기본적으로 final이며 public이다.
클래스 계층 정의
코틀린 인터페이스
- 코틀린 인터페이스 안에는 추상 메서드뿐 아니라 구현이 있는 메서드도 정의할 수 있다. -> Java 8의 default 메서드와 비슷
- 코틀린에서는 default 같은 키워드 따로 추가 안 하고 평범한 메서드처럼 선언하면 됨.
- 다만, 인터페이스에 필드는 들어갈 수 없다.
- 단순한 인터페이스를 구현해보자.
- 자바의 extends와 implements를 코틀린에서는 구분하지 않고 ':'로 모두 처리한다.
- 코틀린에서는 override 변경자는 선택이 아닌 필수로 사용해야 한다.
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!")
}
class Button : Clickable {
override fun click() = println("I was clicked")
override fun showOff() = super<Clickable>.showOff()
}
fun main(args: Array<String>) {
Button().click() // output: I was clicked
Button().showOff() // output: I'm clickable!
}
- clickable 인터페이스에서 showOff() 메서드를 정의했지만 Button에서도 오버라이딩 메서드를 제공해야 한다.
- 위 예제처럼 super 키워드를 통해 인터페이스에서 정의한 메서드를 그대로 사용할 수 있다.
open, final, abstract 변경자
final
- 코틀린은 기본적으로 상속에 대해 열려있지만 클래스와 메서드는 기본적으로 final이다.
open
- 어떤 클래스의 상속을 허용하려면 클래스 앞에 open 변경자를 붙여야 한다.
- 그와 더불어 오버라이드를 허용하고 싶은 메서드나 프로퍼티의 앞에도 open 변경자를 붙여야 한다.
abstract
- abstract로 선언한 추상 클래스는 인스턴스화할 수 없다.
- 추상 클래스에는 구현이 없는 추상 멤버가 있기 때문에 하위 클래스에서 그 추상 멤버를 오버라이드해야만 하는 게 보통이다.
- 이 때문에, 추상 멤버는 항상 open임으로 open 키워드를 붙일 필요가 없다.
Visibility modifier
- 기본적으로 코틀린 가시성 변경자는 자바와 비슷하다.
- public, protected, private 변경자가 있다.
- 코틀린은 자바와 달리 아무 변경자도 없는 경우 선언은 모두 public이다.
- 자바의 기본 가시성인 package-private은 코틀린에 없다.
- 코틀린은 패키지를 namespace를 관리하기 위한 용도로만 사용하기 때문에 package를 가시성 제어에 사용하지 않는다.
- 대신 코틀린에는 internal이라는 가시성 변경자가 있다.
- inernal은 모듈 내부에서만 볼 수 있다는 뜻이다.
- 모듈(module): 한 번에 컴파일되는 코틀린 파일들
- 코틀린에서는 외부 클래스가 내부 클래스나 중첩된 클래스의 private 멤버에 접근할 수 없다.
내부 클래스와 중첩 클래스
- 코틀린의 중첩 클래스(nested class)는 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다.
- 설명 추후 추가
클래스 초기화: 주생성자와 초기화 블록
class User(val nickname: String)
- 위 클래스 선언을 보면 클래스 이름 뒤에 괄호가 있다.
- 이 괄호로 둘러싸인 코드를 주 생성자(primary constructor)라고 부른다.
- 주 생성자는 아래의 두 가지 목적에 쓰인다.
- 생성자 파라미터를 지정
- 그 생성자 파라미터에 의해 초기화되는 프로퍼티를 정의
- 이를 풀어쓰면 다음과 같다.
- constructor: 주 생성자나 부 생성자 정의를 시작할 때 사용
- init: 초기화 블록을 시작. 초기화 블록은 주 생성자와 함께 사용된다. 주 생성자는 제한적이기 때문에 별도의 코드를 포함할 수 없으므로 초기화 블록이 필요하다.
- 초기화 블록을 클래스 안에 여러 개 선언할 수 있다.
class User constructor(_nickname: String) {
val nickname: String
init {
nickname = _nickname
}
}
- 주 생성자 앞에 별다를 어노테이션이나 가시성 변경자가 없다면 constructor를 생략해도 된다.
class User(_nickname: String) {
val nickname = _nickname
}
- 주 생성자의 파라미터로 프로퍼티를 초기화한다면 그 주 생성자 파라미터 이름 앞에 val을 추가하는 방식으로 프로퍼티 정의와 초기화를 간략히 쓸 수 있다.
class User(val nickname: String)
- 디폴트 값을 정의할 수도 있다.
class User(val nickname: String = "hororolol")
- 클래스의 인스턴스를 만들려면 new 키워드 없이 생성자를 직접 호출하면 된다.
val kotlin = User("Kotlin")
println(kotlin.nickname) // output: Kotlin
기반 클래스 초기화
open class Button // 인자가 없는 디폴트 생성자가 자동으로 만들어짐
class RadioButton: Button()
- Button의 생성자는 아무 인자도 받지 않지만, Button 클래스를 상속한 하위 클래스는 반드시 Button 클래스의 생성자를 호출해야 한다.
- 즉, 기반 클래스의 이름 뒤에 꼭 빈 괄호를 넣어줘야 한다. 생성자 인자가 있다면 괄호 안에 인자가 들어간다.
부 생성자: 상위 클래스를 다른 방식으로 초기화
- 코틀린에서는 디폴트 파라미터 값을 줄 수 있으므로 생성자를 여러 개 두는 상황이 적다.
- 그래도 생성자가 여럿 필요한 경우가 가끔 있다.
open class View {
constructor(cts: Context) {
//...
}
constructor(ctx: Context, attr: AttributeSet) {
//...
}
}
class MyButton : View {
constructor(ctx: Context)
: super(ctx) {
//...
}
constructor(ctx: Context, attr: AttributeSet)
: super(ctx, attr) {
//...
}
}
- MyButton 클래스는 주 생성자를 선언하지 않고, 부 생성자만 2가지 선언한다.
- 부 생서자는 constructor 키워드로 시작한다.
- 부 생성자는 여러개 생성할 수 있다.
- 클래스에 주 생성자가 없다면 모든 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에게 생성을 위임해야 한다.
인터페이스에 선언된 프로퍼티 구현
- 코틀린에서는 인터페이스에 추상 프로퍼티 선언을 넣을 수 있다.
interface User {
val nickname: String
}
- 이는 User 인터페이스를 구현하는 클래스가 nickname의 값을 얻을 수 있는 방법을 제공해야 한다는 뜻이다.
- User 인터페이스를 구현하는 방법을 몇 가지 살펴보자.
class PrivateUser(override val nickname: String) : User
- PrivateUser는 주 생성자 안에 프로퍼티를 직접 선언하는 간결한 구문을 사용한다.
- 이 프로퍼티(nickname)는 User의 추상 프로퍼티를 구현하고 있으므로 override를 꼭 표시해야 한다.
class SubscribingUser(val email: String) : User {
override val nickname: String
get() = email.substringBefore('@')
}
- SubscribingUser는 커스텀 getter로 nickname 프로퍼티를 구현한다.
- 이 프로퍼티는 매번 이메일 주소에서 nickname을 계산해서 반환한다.
class FacebookUser(val accountId: Int) : User {
override val nickname = getFacebookName(accountId)
}
- FacebookUser에서는 초기화 식으로 nickname을 초기화한다.
- 이는 객체 초기화 식을 이용하였기 때문에, 한 번만 getFacebookName() 메서드를 호출하게 된다.
프로퍼팅 어떤 값을 저장하되 그 값을 변경하거나 읽을 때마다 정해진 로직을 실행하는 유형의 프로퍼티를 만드는 방법
- 값을 저장하는 동시에 로직을 실행하기 위해서는 접근자 안에서 프로퍼티를 뒷받침하는 필드에 접근할 수 있어야 한다.
- 프로퍼티에 저장된 값의 변경 이력을 로그에 남기려는 경우를 생각해보자.
class User(val name: String) {
var address: String = "unspecified"
set(value: String) {
println("""
Address was changed for $name: "$field" -> "$value" // 뒷받침하는 필드 값 읽기
""".trimIndent())
field = value // 뒷받침하는 필드 값 변경
}
}
fun main(args: Array<String>) {
val user = User("Alice")
user.address = "Elsenheimerstrasses 47"
// output: Address was changed for Alice: "unspecified" -> "Elsenheimerstrasses 47"
}
- $field: 현재 address 주소
- $value: 새로운 address 주소
- field라는 식별자를 통해 뒷받침하는 필드에 접근할 수 있다.
Private setter가 있는 프로퍼티
class LengthCounter {
var counter: Int = 0
private set // counter 프로퍼티 값을 클래스 밖에서 바꿀 수 없음
fun addWord(word: String) {
counter += word.length
}
}
fun main(args: Array<String>) {
val lengthCounter = LengthCounter()
lengthCounter.addWord("Hi!")
println(lengthCounter.counter) // output: 3
// lengthCounter.counter = 4 -> error
}
출처:
- [Kotlin IN ACTION]
반응형
'Programming Language > Kotlin' 카테고리의 다른 글
[Kotlin] 람다 식(lambda expression)과 멤버 참조 (0) | 2021.06.16 |
---|---|
[Kotlin] 클래스와 인터페이스2 - 데이터 클래스/클래스 위임/object 키워드 사용 (0) | 2021.06.15 |
[Kotlin] 함수 정의와 호출1 - 컬렉션/확장 함수/로컬 함수/문자열을 정규식으로 나누기 (0) | 2021.06.12 |
[Kotlin] 코틀린 기초2 - 스마트 캐스트, 이터레이션(for 문, 컬렉션이나 원소 검사), 예외 처리 (0) | 2021.06.11 |
[Kotlin] 코틀린 기초1 - 함수, 변수, 클래스, property, enum, when (1) | 2021.06.10 |
Comments