상속 받을 클래스에서 구현해야 할 프로퍼티 및 메서드를 기술한 클래스
// 추상 클래스, 주 생성자에는 비추상 프로퍼티 선언의 매개변수 3개가 있음
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") }
}
class Car(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
override fun start() {
println("Car Started") // 코드의 구현
}
override fun stop() {
println("Car Stopped") // 코드의 구현
}
}
class Motorcycle(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
override fun start() {
println("Bike Started") // 코드의 구현
}
override fun stop() {
println("Bike Stopped") // 코드의 구현
}
}
fun main() {
val car = Car("SuperMatiz", "yellow", 1110.0, 270.0)
val motor = Motorcycle("DreamBike", "red", 173.0, 100.0)
car.year = "2013"
car.displaySpecs()
car.start()
motor.displaySpecs()
motor.start()
}
Name: SuperMatiz, Color: yellow, Weight: 1110.0, Year: 2013, Max Speed: 270.0
Car Started
Name: DreamBike, Color: red, Weight: 173.0, Year: 2018, Max Speed: 100.0
Bike Started
각각의 하위 클래스에서 오버라이딩 한 함수대로 출력이 된다
자바와 동일하게 구현부가 없는 method + default method의 집합으로
interface Clickable {
fun click()
fun showOff(){
println("Clickable.showOff")
}
}
interface Focusable{
fun showOff(){
println("Focusable.showOff")
}
}
class Button : Clickable, Focusable {
override fun click() {
println("Button.click")
}
//showOff는 두 슈퍼에 모두 존재하므로, 동일하게 애매함을 없애기 위해서 반드시 선언.
//super에 선언된 fun을 호출할때는 super<Clickable>.showOff()
//java에서는 Clickable.super.showOff();
override fun showOff() {
println("Button.showOff")
}
}
fun main() {
var button = Button()
button.click()
button.showOff()
}
일반 클래스와 달리 소괄호로 프로퍼티를 선언하기만 한다.
자동으로 toString(), equals(), hashCode()를 만들어준다. (setter, getter 역시 자동생성)
즉, 자바의 DTO 클래스와 같은 역할을 하기 위해 사용한다.
data class Ticket(val comapyName : String, val name : String, var date : String, var seatNumber : Int)
class Ticket2(val comapyName : String, val name : String, var date : String, var seatNumber : Int)
//toString(), hanshCode(), equals(), copy()
fun main(){
val tickets = Ticket("KoreanAir", "Lee", "2022-6-29",20)
val tickets2 = Ticket2("KoreanAir", "Lee", "2022-6-29",20)
println(tickets)
println(tickets2)
}
결과:
Ticket(comapyName=KoreanAir, name=Lee,date=2022-6-29, seatNumber=20)
com.example.myapplication.Ticket2@2d6e8792
object 키워드로 클래스를 만들면 싱글턴 클래스가 된다
object MyObject {
var name: String = ""
var type: String = ""
var age: Int = 0
fun myType() {
println("my name is $name and type is $type age is $age")
}
}
fun main() {
val name = "samsung"
val type = "ENFP"
val age = 23
MyObject.name = name
MyObject.type = type
MyObject.age = age
MyObject.myType()
println("${MyObject.name} and ${MyObject.type} and ${MyObject.age}")
}
my name is samsung and type is ENFP age is 23
samsung and ENFP and 23
인자 없는 열거형 클래스
enum class SsafyHandsome {
SSAFY, LOVE, PEACE
}
fun main() {
val ssafyEnum: SsafyHandsome = SsafyHandsome.SSAFY
println("${ssafyEnum.name} ... ${ssafyEnum.ordinal}")
val ssafyEnum2: Array<SsafyHandsome> = SsafyHandsome.values()
for (i in ssafyEnum2.indices) {
println(ssafyEnum2[i].name)
}
}
인자가 있는 열거형 클래스
enum class Human(val age: Int) {
KIM(25), CHOI(21)
}
fun main() {
val human: Human = Human.KIM
println("${human.name}, ${human.age}, ${human.ordinal}")
}
부모 클래스의 상속을 받는 자식 클래스의 종류를 제한하는 클래스이다.
package com.android.example.kotlinproject.kotlinadvanced
sealed class Color {
object Red : Color()
object Green : Color()
object Blue : Color()
}
fun main() {
val color: Color = Color.Red
// val font = when (color) {
// is Color.Red -> {
// "Noto Sans"
// }
// is Color.Green -> {
// "Open Sans"
// }
// // compile error!
// }
val font = when (color) {
is Color.Red -> "Noto Sans"
is Color.Green -> "Open Sans"
is Color.Blue -> "sans-serif"
// No error! 왜냐하면 Color형은 red,green,blue만 가진다고 sealed 클래스에서 알렸기 때문이다.
}
println("결정된 font는 : $font")
}
위 코드에서 when 절에서 else를 넣지 않아도 오류가 나지 않는다. 컴파일 타임에서 이미 color가 3개밖에 없다는 것을 sealed 클래스에서 인지시키고 있기 때문이다.
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
다음처럼도 선언 가능
공통점
차이점
코틀린에서는 단순히 클래스 안에 클래스를 정의하면 자바와 달리(자바는 내부클래스가 됨) 중첩 클래스가 된다. 이렇게 되면 바깥 클래스의 member에 접근할 수도 없다.
따라서 내부 클래스를 만들기 위해 inner 키워드로 클래스를 선언한다.
매개 변수나 함수의 반환 값으로 함수가 사용되는 함수
인자로 람다함수를 받아서 정수값을 리턴하는 함수
private fun highOrderFunction(sum: (Int, Int) -> Int, a: Int, b: Int): Int = sum(a, b)
println(highOrderFunction({ x, y -> x + y }, 20, 30))
ex) ::함수으로 일반함수 레퍼런스를 가져와 람다함수를 넣는 자리에 일반함수를 넣을 수 있다.
private fun sum(a: Int, b: Int): Int = a + b
private fun highOrderFunction(cal: (Int, Int) -> Int, a: Int, b: Int): Int = cal(a, b)
println(highOrderFunction(::sum, 20, 30))
val multiply:(Int, Int) -> Int = { x: Int, y: Int -> x * y }
println("곱셈 결과 = ${multiply(8, 8)}")
println("곱셈 결과 = ${highOrderFunction(multiply, 8,8)}")
println(highOrderFunction(20, 30, { x, y -> x + y })
와 같이 람다식이 마지막 인자라면
var result = highOrderFunction(20, 30){
x, y -> x + y
}
println(result)
}
람다를 인자로 받아 동작하는 함수
let()을 호출하는 객체의 람다식 안에 파라미터로 넘김
it을 통해 호출 객체에 접근
블럭의 결과값을 반환
var arr = arrayOf(1, 2, 3)
var result = arr.let {
println("${it[1] + it[2]}")
it[1] + it[2]
} //let 람다식 계산 결과를 리턴
5
5
더하기 결과: 6
also()을 호출하는 객체의 람다식 안에 파라미터로 넘김
it을 통해 호출 객체에 접근
호출 객체 자체를 반환
var student2 = student.also {
it.age = 15
it.name = "kim"
}
Student(name=kim, age=15)
apply()을 호출하는 객체의 람다식 안에 파라미터로 넘김
this를 통해 호출 객체에 접근
let, also와 달리 it이 아닌 this로 객체를 받음
this는 생각 가능
fun applyTest() {
var student = Student2("Park", 11)
var student2 = student.apply {
age = 15 //this 생략
name = "kim" //this 생략
}
println(student) //Student2(name=kim, age=15)
println(student2) //Student2(name=kim, age=15)
}
호출 객체를 파라미터를 넘기거나, 객체 없이 사용하는 방식 둘다 가능
블럭의 결과값을 반환
let, also와 달리 it이 아닌 this로 객체를 받음
fun runTest() {
var a = 10
var b = 15
//객체없이 run 단독 사용
var result = run {
var c = a + b
println(c) //25
c
}//더하기 작업 수행 후 결과 c 반환
//객체에 run 사용.
result = result.run {
plus(5)
}
println(result) //30
25
30
fun withTest(){
var people = People("Park", 15)
var newAge = with(people){
age = 20
age
}
println(newAge) //20
}