[코틀린의 기본 문법 2]
class (클래스)
class Person { } // 빈 클래스 형태
class Person { // 생성자를 정의한 클래스 (*k1)
constructor(name: String) {
println(name)
}
}
희한하게 클래스를 아래 처럼도 정의하는군요...
class Person (var name: String) { } // (생성자를 갖는) 빈 클래스 (참고: var 생략 가능)
// 굳이 클래스명 옆에 이런 문법을 만들것 까지야...
// 메소드 오버로드는 없나보군요...
class Person (name: String) {
init { // init 블럭은 생성자와 함께 제일 먼저 실행됨 (위 *k1과 동일 결과)
println(name)
}
}
var person1 = Person("원빈") // 개체 생성
person1.name = "한효주" // 프로퍼티 쓰기
println(person1.name) // 프로퍼티 읽기
접근 제한자
public : (생략가능) 전체 공개
private : 현재 파일 내에서만 공개
internal : 같은 모듈 내에서만 공개 (모듈? 예를 들면, 한 프로젝트 내에 스마트폰용 모듈, 시계용 모듈, TV용 모듈,
태블릿용 모듈 등등 여러 모듈들을 제작하는 경우가 있음. 모듈은 여러 개의 파일 조각으로 이뤄져 있음)
protected : 부모로 부터 상속받은 클래스에서만 공개
클래스 상속
※ 코틀린에서는 기본적으로 상속을 금지합니다. (추상 클래스 제외)
그러나 꼭 사용하고자 한다면 open 키워드를 사용할 수 있습니다.
빈 클래스 상속
open class Animal { }
class Dog : Animal( ) { } // SHS: 반드시 상위 클래스의 생성자를 호출하는 형식임
생성자를 갖는 클래스의 상속
open class Animal(val name: String) { }
class Dog(name: String) : Animal(name) { }
중첩 클래스
안쪽 클래스는 바깥 클래스A와 거의 독립적입니다.
안쪽과 바깥쪽 변수명이 같아도 됩니다. 단지 선언된 위치가 클래스A 안쪽일 뿐입니다.
class A {
class B { // 중첩 클래스
}
}
var bb = A.B( ) // 클래스B의 위치를 명시하고 클래스B를 객체화 할 수 있음.
(중첩된) 내부 클래스
안쪽 클래스에 inner 키워드를 붙여주면 바깥 클래스 멤버에 접근할 수 있고,
이 때의 내부 클래스B는 클래스A의 멤버로 소속이 바뀝니다.
class A {
var a=10
inner class B { // (중첩된) 내부 클래스 - 멤버가 된 클래스
fun result( ) {
a = 20 // 바깥 클래스 멤버에 접근 가능
}
}
}
var bb = A( ).B( ) // 클래스B는 클래스A의 멤버이므로 객체화된 바깥 클래스를 통해서만 객체화가 가능
추상 클래스
미구현 메소드가 포함된 클래스를 의미하죠. 키워드: abstract
클래스명과 미구현 메소드명 앞 모두에 키워드를 작성해야 합니다.
미구현 메소드가 단 한 개라도 포함되어 있다면 추상 클래스 입니다.
추상 클래스는 반드시 상속을 목적으로 제작하는 클래스입니다.
반드시 상속한 후, 미구현 메소드를 구현해야 합니다.
이것은 반드시 지켜야 하는 개발 팀원들 간의 약속입니다.
abstract class A {
abstract fun func1( ) { }
fun func2( ) { }
}
class B: A( ) {
override fun func3( ) {
println("Hello")
}
}
인터페이스
추상 클래스와 거의 같지만, 일단 2가지 큰 차이점이 있습니다.
1. 추상 클래스는 하나만 상속 가능
인터페이스는 복수 개를 상속 받을 수 있음 ('다중 상속')
2. 추상 클래스 내부에는 추상 메소드만 선언 가능 (abstract 키워드 필수)
인터페이스 내부에서는 추상 메소드 + 일반 메소드 모두 사용가능 (abstract 키워드 불필요)
interface Runable {
fun run( ) // { } 코드가 없는 추상 메소드
fun walk( ) = println("걷는다") // 일반 메소드 포함 가능
}
class Human : Runable {
override fun run( ) { println("달린다") }
}
※ 상속과 인터페이스를 함께 사용해본 예)
class Animal { ... }
interface Runable { ... }
interface Eatable { ... }
class Dog : Animal( ), Runable( ), Eatable( ) { ... } // 클래스 상속과 인터페이스 다중 상속
(계속...)