1. 추상 클래스 (Abstract Class)
- 구현 클래스에서 가져야할 명세를 정의한 클래스
abstract
라는 키워드와 함께 선언하며 추상클래스는 객체 생성 안됨
- 구체적이지 않은 것을 나타내기 때문에 하위 파생 클래스에서 구체적으로 구현
- open 키워드를 사용하지 않고도 파생 클래스 작성 가능
abstract class Vehicle(val name: String, val color: String, val weight: Double) {
abstract var maxSpeed: Double
var year = "2018"
abstract fun start()
abstract fun stop()
fun displaySpecs() {
println("Name: $name, Color: $color,
Weight: $weight, Year: $year, Max Speed: $maxSpeed")
}
}
2. Interface
interface Pet {
var category: String
fun feeding()
fun patting() {
println("Keep patting!")
}
}
- 현실세계의 계약서 역할
- 다른 언어와는 다르게 기본적인 구현 내용이 포함될 수 있다
- java8에서
default
키워드로 구현내용을 생성가능
- 상속한 하위 클래스에서는 override 를 사용해 해당 메서드를 구현
- 인터페이스에서는 프로퍼티에 값을 저장 할 수 없지만 val 로 선언된 프로퍼티는 getter를 통해 필요한 내용을 구현가능
- 클래스가 아니므로 다양한 인터페이스로부터 클래스 구현가능 (다중상속)
interface Bird {
val wings: Int
fun fly()
fun jump() = println("bird jump!")
}
interface Horse {
val maxSpeed: Int
fun run()
fun jump() = println("jump!, max speed: $maxSpeed")
}
class Pegasus: Bird, Horse {
override val wings: Int = 2
override val maxSpeed: Int = 100
override fun fly() = println("Fly!")
override fun run() = println("Run!")
override fun jump() {
super<Horse>.jump()
println("and Jump!")
}
}
3. DTO (Data Transfer Object)
data class Customer(var name: String, var email: String)
- 자바에서
POJO(Plaint Old Java Object)
에 해당
- 구현 로직은 없고 순수한 데이터 객체를 표현
- getter/setter 를 포함
- 주 생성자는 최소한 하나의 매개변수를 가져야 한다
- 주 생성자는 모든 매개변수는 val, var 로 지정된 프로퍼티여야 한다
- 데이터 클래스는 abstract, open, sealed, inner 키워드를 사용할 수 없다
- 자동 생성 메서드들
equals()
: 고유값은 다르지만 의미값이 같을 때 사용
hashCode()
: 객체를 구별하기 위한 고유한 정수값 생성
copy()
: 빌더 없이 특정 프로퍼티만 변경해서 객체 복사하기
toString()
: 데이터 객체를 읽기 편한 문자열로 반환하기
componentN()
: 객체의 선언부 구조를 분해하기 위해 프로퍼티에 상응하는 메서드
예시
data class Customer(val name: String, val email : String) {
val job : String = "unknown"
constructor(name: String, email :String, _job:String) : String(name :email) {
job = _job
}
init {
}
}
equals()와 hashCode() 예시
val cus1 = Customer("Sean", "sean@email.com")
val cus2 = Customer("Sean", "sean@email.com")
..
println(cus1 == cus2)
println(cus1.equals(cus2))
println(${cus1.hashCode()}, ${cus2.hashCode()})
copy() 예시
val cus3 = cus1.copy(name = "Alice")
println(cus1.toString())
println(cus3.toString())
3.1. 객체 디스트럭처링(destructuring)
val (name, email) = cus1
println("name = $name, email = $email")
val (_, email) = cus1
4. 내부 클래스
자바 | 코틀린 |
---|
정적 클래스 (Static Class) | 중첩 클래스(Nested Class) : 객체 생성 없이 사용 가능 |
멤버 클래스 (Member Class) | 이너 클래스(Inner Class) : 필드나 메서드와 연동하는 내부클래스, inner 키워드 필수 |
지역 클래스 (Local Class) | 지역 클래스(Local Class) : 클래스의 선언이 블록에 있다면 지역 클래스 |
익명 클래스 (Anonymous Class | 익명 객체(Anonymous Object) : 이름이 없고 주로 일회용 객체를 사용하기 위해 object 키워드를 통해 선언 |
4.1. Inner class 와 Nested Class
사용법이 자바와 많이 달라서 주의해야 한다.
class A {
inner class B {
}
}
class A {
class B {
}
}
Nested 또는 Inner 클래스가 아닌 경우 companion object
를 이용해서 바깥 클래스에 접근 할 수 있습니다.
- Nested Class
- Inner Class
- 이너 클래스는 바깥 클래스의 멤버들에게 접근 가능
- 바깥 클래스의 private 멤버도 접근이 가능
4.2. Local Class
- 특정 메서드 블록, init 블록과 같이 블록 범위에만 유효
- 블록 범위를 벗어나면 사용 불가
4.3. Anonymous Class
- 익명 클래스
- object 키워드를 사용하는 익명 객체로 일회성 객체를 생성ㅇ해 사용한다
4.4. Sealed Class
- 실드란 '봉인된' 이라는 의미로 무언가 안전하게 보관하기 위해 묶어두는 것
- sealed 키워드를 class와 함께 사용
- 실드 클래스 그 자체로는 추상 클래스와 같기 때문에 객체를 만들 수는 없다
- private 의 생성자만 허용 가능
- 같은 파일 안에서는 상속가능 다른 파일에서는 상속 불가
- 블록 안에 선언되는 클래스는 상속이 필요한 경우 open 키워드로 선언
sealed class Result {
open class Success(val message: String): Result()
class Error(val code: Int, val message: String): Result()
}
class Status: Result()
class Inside: Result.Success("Status")
sealed class Result
open class Success(val message:String) :Result()
class Error(val code:Int, val message: String) :Result()
class Status: Result()
class Inside: Success("Status")
- when 구문을 작성시 if-else 문을 사용하지 않는다
fun eval(result: Result): String = when(result) {
is Status -> "In progress"
is Result.Success -> result.message
is Result.Error -> result.message
}
4.5. Enum Class
- 여러개의 상수를 선언하여 조건에 따로 선택할 수 있는 특수 클래스
- 실드 클래스와 거이 비슷하지만 다양한 자료형을 다루지 못함
예시
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
각 상수는 Direction 클래스의 객체로 취급되고 콤마로 구분
enum class DayOfWeek(val num:Int) {
MONDAY(1), TUESDAY(2), WENDSDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7)
}
메서드가 포함되는 경우
enum class Color(val r:Int, val g:Int, val b:Int) {
RED(255, 0, 0), BLUE(0, 0, 255), YELLOW(255,255,0);
fun rgb = (r * 256 + g) * 256 + b
}
fun main() {
println(Color.BLUE.rgb())
}
4.6. Annotation Class
- 부가 정보를 추가하는 기능 역할
- @ 기호화 함께 컴파일러 프로그램 실행 기간에서 사전 처리를 위해 주로 사용
- 속성
@Target
: 애노테이션이 지정되어 사용할 종류(클래스, 함수, 프로퍼티 등)를 정의
@Retention
: 애노테이션을 컴파일된 클래스 파일에 저장할 것인지 실행 시간에
반영할 것인지 결정
@Repeatable
: 애노테이션을 같은 요소에 여러 번 사용 가능하게 할지를 결정
@MustBeDocumented
: 애노테이션이 API의 일부분으로 문서화하기 위해 사용
5. 연산자 오버로딩
- 연산자에 여러 가지 다른 의미의 작동을 부여
- 코틀린에서는 특정 연산자의 역할을 함수로 정의
operator
키워드를 사용해 정의
5.1. 수식 연산자
표현식 | 함수 의미 |
---|
a+b | a.plus(b) |
a-b | a.minus(b) |
a*b | a.times(b) |
a/b | a.div(b) |
a%b | a.rem(b) |
a..b | a.rangeTo(b) |
5.2. 호출 연산자
- invoke operator 함수 호출을 돕는데 사용한다
5.3. 인덱스 연산자
- getter/setter 를 다루기 위한 대괄호 연산자 제공
표현식 | 함수 의미 |
---|
a[i] | a.get(i) |
a[i,j] | a.get(i,j) |
a[1_1,...,i_n] | a.get(i_1,...i_n) |
a[i] =b | a.set(i, b) |
a[i,j] =b | a.set(i,j,b) |
a[i_1,...,i_n] = b | a.set(i_1,...,i_n, b) |
5.4. 단일연산자
표현식 | 함수 의미 |
---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
5.5. 포함 범위 연산자
표현식 | 함수 의미 |
---|
a in b | b.contains(a) |
a in b | !b.contains(a) |
5.6. 할당 연산자
표현식 | 함수 의미 |
---|
a += b | a.plusAssign(b) |
a -= b | a.minusAssign(b) |
a *= b | a.timesAssign(b) |
a /= b | a.divAssign(b) |
a %= b | a.remAssign(b) |
5.7. 동등성 연산자
표현식 | 함수 의미 |
---|
a == b | a?.equals(b) ?: (b === null) |
a != b | !(a?.equals(b) ?: (b === null)) |
5.8. 비교 연산자
표현식 | 함수 의미 |
---|
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a <= b | a.compareTo(b) <= 0 |
Reference