++ 상속(inheritance) ++
- 자식 클래스를 만들 때 상위 클래스(부모 클래스)의 속성과 기능을 물려받아 계승
- 상위(부모) 클래스의 프로퍼티와 메서드가 자식에 적용됨
- open 키워드를 통한 선언
open class 기반 클래스명 { // open으로 파생 가능 (다른 클래스가 상속 가능한 상태가 됨)
...
}
class 파생 클래스명 : 기반 클래스명() { // 기반 클래스로부터 상속, 최종 클래스로 파생 불가
...
}
** 코틀린의 모든 클래스는 묵시적으로 Any로부터 상속 (자바에서의 Object가 코틀린의 Any라고 생각하면 된다.)
super(...) : 상위클래스 생성자 호출
++ 다형성(polymorphism) ++
- 같은 이름을 사용하지만 구현 내용이 다르거나 매개변수가 달라서 하나의 이름으로 다양한 기능을 수행할 수 있는 개념
++ 오버라이딩(overriding) ++
- 기능을 완전히 다르게 바꾸어 재설계
** 누르다 -> 행위 -> push()
- push()는 '확인' 혹은 '취소' 용도로 서로 다른 기능을 수행 할 수 있음
- 상속과 관련
++ 오버로딩(overloading) ++
- 기능은 같지만 인자를 다르게 하여(파라미터를 다르게 하여) 여러 경우를 처리
** 출력한다 -> 행위 -> print()
- print(123), print("Hello") 인자는 다르지만 출력의 기능은 동일함
- 오버로딩의 일반함수의 예시
// 정수 자료형 매개변수 2개를 더함
fun add(x: Int, y: Int): Int {
return x + y
}
// 실수 자료형 매개변수 2개를 더함
fun add(x: Double, y: Double): Double {
return x + y
}
// 정수 자료형 매개변수 3개를 더함
fun add(x: Int, y: Int, z: Int): Int {
return x + y + z
}
package com.example.pp129
// 상속 가능한 클래스를 위해 open 사용
open class Bird(var name: String, var wing: Int, var beak: String, var color: String) {
// 메서드
fun fly() = println("Fly wing: $wing")
fun sing(vol: Int) = println("Sing vol: $vol")
}
// 주 생성자를 사용하는 상속
class Lark(name: String, wing: Int, beak: String, color: String) : Bird(name, wing, beak, color) {
fun singHitone() = println("Happy Song!") // 새로 추가된 메서드
}
// 부 생성자를 사용하는 상속
class Parrot: Bird {
val language: String
constructor(name: String, wing: Int, beak: String, color: String, language: String) : super(name, wing, beak, color) {
this.language = language // 새로 추가된 프로퍼티
}
fun speak() = println("Speak! $language")
}
fun main() {
val coco = Bird("mybird", 2, "short", "blue")
val lark = Lark("mylark", 2, "long", "brown")
val parrot = Parrot("myparrot", 2, "short", "multiple", "korean") // 프로퍼티가 추가됨
println("Coco: ${coco.name}, ${coco.wing}, ${coco.beak}, ${coco.color}")
println("Lark: ${lark.name}, ${lark.wing}, ${lark.beak}, ${lark.color}")
println("Parrot: ${parrot.name}, ${parrot.wing}, ${parrot.beak}, ${parrot.color}, ${parrot.language}")
lark.singHitone() // 새로 추가된 메서드가 사용
parrot.speak()
lark.fly()
}
파생 클래스 만들어보기
- 하위 클래스는 상위 클래스의 메서드나 프로퍼티를 그대로 상속하면서
상위 클래스에는 없는 자신만의 프로퍼티나 메서드를 확장
package com.example.pp134
fun main() {
val calc = Calc()
println(calc.add(3, 2))
println(calc.add(3.2, 1.3))
println(calc.add(3, 3, 2))
println(calc.add("Hello", "World"))
}
class Calc {
// 다양한 매개변수로 오버로딩된 메서드들
fun add(x: Int, y: Int): Int = x + y
fun add(x: Double, y: Double): Double = x + y
fun add(x: Int, y: Int, z: Int): Int = x + y + z
fun add(x: String, y: String): String = x + y
}
클래스 메서드의 오버로딩
- 덧셈 동작의 오버로딩
++ 오버라이딩 (Overriding) ++
- ‘(기존의 작업을) 중단하다’, ‘뒤엎다’ 등으로 해석
- 상위 클래스의 메서드의 내용을 완전히 새로 만들어 다른 기능을 하도록 정의
- 오버라이딩하기 위해 부모 클래스에서는 open 키워드,
자식 클래스에서는 override 키워드를 각각 이용
- 메서드 및 프로퍼티등에 사용할 수 있다.
- 메서드 오버라이딩 예시
open class Bird { // 여기의 open은 상속 가능을 나타냄
...
fun fly() { ... } // 최종 메서드로 오버라이딩 불가
open fun sing() {...} // sing() 메서드는 하위 클래스에서 오버라이딩 가능
}
class Lark() : Bird() { // 하위 클래스
fun fly() { /* 재정의 */ } // 에러! 상위 메서드에 open키워드가 없어 오버라이딩 불가
override fun sing() { /* 구현부를 새롭게 재정의 */ } // 구현부를 새롭게 작성
}
- 오버라이딩 금지
** 파생 클래스에서 오버라이딩을 금지할 때
open class Lark() : Bird() {
final override fun sing() { /* 구현부를 새롭게 재정의 */ } // 하위 클래스에서 재정의 금지
}
package com.example.pp138
// 상속 가능한 클래스를 위해 open 사용
open class Bird(var name: String, var wing: Int, var beak: String, var color: String) {
// 메서드
fun fly() = println("Fly wing: $wing")
open fun sing(vol: Int) = println("sing vol: $vol") // 오버라이딩 가능한 메서드
}
class Parrot(name: String, wing: Int = 2, beak: String, color: String, // 마지막 인자만 var로 선언되어 프로퍼티가 추가됨
var language: String = "natural"): Bird(name, wing, beak, color) {
fun speak() = println("Speak! $language") // Parrot에 추가된 메서드
override fun sing(vol: Int) { // 오버라이딩된 메서드
println("I'm a parrot! The volume level is $vol")
speak() // 달라진 내용
}
}
fun main() {
val parrot = Parrot(name="myparrot", beak="short", color="multiple")
parrot.language = "English"
println("Parrot: ${parrot.name}, ${parrot.wing}, ${parrot.beak}, ${parrot.color}, ${parrot.language}")
parrot.sing(5) // 달라진 메서드 실행 기능
}
메서드 오버라이딩 하기
++ super, this ++
- 현재 클래스에서 참조의 기능
- 상위 클래스는 super 키워드로 현재 클래스는 this 키워드로 참조가 가능
super
- super.프로퍼티명 // 상위 클래스의 프로퍼티 참조
- super.메서드명( ) // 상위 클래스의 메서드 참조
- super( ) // 상위 클래스의 생성자의 참조
this
- this.프로퍼티명 // 현재 클래스의 프로퍼티 참조
- this.메서드명( ) // 현재 클래스의 메서드 참조
- this( ) // 현재 클래스의 생성자의 참조
package com.example.pp140
open class Bird100(var name: String, var wing: Int, var beak: String, var color: String) {
fun fly() = println("Fly wing: $wing")
open fun sing(vol: Int) = println("Sing vol: $vol")
}
class Parrot100(name: String, wing: Int = 2, beak: String, color: String,
var language: String = "natural") : Bird100(name, wing, beak, color) {
fun speak() = println("Speak! $language")
override fun sing(vol: Int) { // 부모의 내용과 새로 구현된 내용을 가짐
super.sing(vol) // 상위 클래스의 sing()을 먼저 수행
println("I'm a parrot! The volume level is $vol")
speak()
}
}
fun main() {
val parrotmo = Parrot100("leemiso", 4, "long", "orange")
parrotmo.sing(4)
}
super로 상위 참조
- 상위 클래스의 메서드 실행
package com.example.pp142
open class Person {
constructor(firstName: String) {
println("[Person] firstName: $firstName")
}
constructor(firstName: String, age: Int) {
println("[Person] firstName: $firstName, $age")
}
}
class Developer: Person {
constructor(firstName: String): this(firstName, 10) {
println("[Developer] $firstName")
}
constructor(firstName: String, age: Int): super(firstName, age) {
println("[Developer] $firstName, $age")
}
}
fun main() {
val hahee = Developer("Hahee")
}
this와 super를 사용하는 부 생성자
package com.example.pp143
class Person(firstName: String,
out: Unit = println("[Primary Constructor] Parameter")) { // 주 생성자
val fName = println("[Property] Person fName: $firstName") // 프로퍼티 할당
init {
println("[init] Person init block") // 초기화 블록
}
// 보조 생성자
constructor(firstName: String, age: Int,
out: Unit = println("[Secondary Constructor] Parameter")): this(firstName) {
println("[Secondary Constructor] Body: $firstName, $age") // 부 생성자 본문
}
}
fun main() {
val p1 = Person("Kildong", 30)
println()
val p2 = Person("Dooly")
}
주 생성자와 부 생성자 함께 사용하기
** 순서 꼭 알아야함. (처리 로직)
++ 바깥 클래스 호출하기 ++
- @(엣) 기호의 이용
- 이너 클래스에서 바깥 클래스의 상위 클래스를 호출하려면
super 키워드와 함께 엣(@) 기호 옆에 바깥 클래스명을 작성해 호출
*** 인터페이스는 소괄호 xxxxxx
interface B {...}
class C : A(), B {...}
package com.example.pp146
open class Base {
open val x: Int = 1
open fun f() = println("Base Class f()")
}
class Child: Base() {
override val x: Int = super.x + 1
override fun f() = println("Child Class f()")
inner class Inside {
fun f() = println("Inside Class f()")
fun test() {
f() // 현재 이너 클래스 f() 접근
Child().f() // 바로 바깥 클래스 f()의 접근
super@Child.f() // Child의 상위 클래스인 Base 클래스의 f() 접근
println("[Inside] super@Child.x: ${super@Child.x}") // Base의 x 접근
}
}
}
fun main() {
val c1 = Child()
c1.Inside().test() // 이너 클래스 Inside의 메서드 test() 실행
}
이너 클래스에서 바깥 클래스 접근하기
package com.example.pp147
open class A {
open fun f() = println("A Class f()")
fun a() = println("A Class a()")
}
interface B {
fun f() = println("B Interface f()") // 인터페이스는 기본적으로 open임
fun b() = println("B Interface b()")
}
class C : A(), B { // 콤마,를 사용해 클래스와 인터페이스를 지정
// 컴파일되려면 f()가 오버라이딩되어야 한다.
override fun f() = println("C Class f()")
fun test() {
f() // 현재 클래스의 f()
b() // 인터페이스 B의 b()
super<A>.f() // A 클래스의 f()
super<B>.f() // B 클래스의 f()
}
}
fun main() {
val c = C()
c.test()
}
앵글브라켓을 사용한 이름 중복 해결
'Kotlin' 카테고리의 다른 글
Kotlin #8 : 코틀린의 프로퍼티, 자바의 필드, 지연 초기화, lazy, 위임 230220 (0) | 2023.02.22 |
---|---|
Kotlin #7 : 정보 은닉 캡슐화 (연관, 의존, 집합, 구성) 230220 (0) | 2023.02.20 |
Kotlin #5 : 객체지향 프로그래밍 230216 (0) | 2023.02.17 |
Kotlin #4 : 예외처리 230216 (0) | 2023.02.16 |
Kotlin #3 : 기본 연산자, 비트 연산자, 변수와 함수, 반복문, 조건문, 람다식 230213 (0) | 2023.02.15 |
댓글