1. 클래스를 상속하는 객체
클래스 없이 object 표현식을 사용해 상속을 할 수 있다. 이때의 상속은 1회용이 된다.
open class Person(val name: String, val age: Int) {
open fun print() {
println("이름:$name, 나이:$age")
}
}
fun main(args: Array<String>) {
val custom: Person = object : Person("Alan", 23) {
override fun print() {
println("it's a object")
}
}
custom.print()
}
2. Any 클래스
모든 코틀린 클래스들은 Any 클래스를 상속한다.
open class Any {
open operator fun equals(other: Any?): Boolean
open fun hashCode(): Int
open fun toString(): String
}
- equals() : == 연산자를 오버로딩하는 멤버 함수
- hashCode() : 객체 고유의 해시코드를 반환하는 멤버 함수
- toString() : 객체의 내용을 String 타입으로 반환하는 멤버 함수
class Person(val name: String, val age: Int) {
override fun toString() = "이름:$name 나이:$age"
}
fun main(args: Array<String>) {
val custom = Person("a", 23)
println(custom.toString())
}
3. Nothing 타입
Nothing은 리턴이라는 행위 자체를 하지 않음을 뜻한다.
fun throwing(): Nothing = throw Exception()
fun main(args: Array<String>) {
println("start")
val i: Int = throwing()
println(i)
}
위의 예제에서 if 블록은 Int 타입, else 블록이 Nothing 타입이면, if-else는 Int 타입을 따라간다. Nothing 타입은 throw를 표현식으로 쓸 수 있게 하기 위한 장치다.
4. Nullable 타입과 null
Nullable이란, null 값을 지정할 수 있는 변수를 뜻한다. 타입 이름 뒤에 ?를 붙이면 변수를 Nullable하게 만들 수 있다.
fun main(args: Array<String>) {
val str : String? = if (true) "test" else null
}
"test"는 String, null은 Nothing? 타입이므로, if-else 표현식의 타입은 이 둘이 합쳐진 String?이 된다.
5. 안전한 호출 연산자 - ?.
Nullable한 참조 변수의 프로퍼티와 멤버 함수에 접근하려면 . 대신 ?. 연산자를 사용해야 한다.
class Building(var name: String){
fun print(){
println("name : $name")
}
}
fun main(args: Array<String>) {
var obj: Building? = null
obj?.print() // print() 함수가 호출되지 않는다.
obj = Building("백화점")
obj?.print() // print() 함수 호출된다.
}
6. Not-null 단정 연산자 - !!
!! 연산자는 Nullable 타입을 Not-null 타입으로 강제로 캐스팅한다.
class Building(var name: String)
fun main(args: Array<String>) {
val obj: Building? = null
obj!!.name = "백화점"
}
obj는 null이기 때문에 obj!!.name에서 KotlinNullPointerException이 발생한다.
7. 엘비스 연산자 - ?:
엘비스 연산자는 왼쪽의 피연산자가 null이 아니면 그 값을 그대로 쓰고, null이면 우측의 피연산자로 대체하는 연산자이다.
fun main(args: Array<String>) {
val num1: Int? = null
println(num1 ?: 0) // 0
val num2: Int? = 15
println(num2 ?: 0) // 15
}
8. 스마트 캐스팅
특정 조건을 만족하는 경우, 컴파일러는 변수의 타입을 다른 타입으로 자동 캐스팅하는 것을 스마트 캐스팅이라 한다.
fun main(args: Array<String>) {
val num1: Int? = null
val num2 = 1225
checkNull(num1)
checkNull(num2)
}
fun checkNull(any: Any?) {
if (any == null) {
println("null이 들어왔습니다.")
return
}
println(any.toString())
}
if (any == null) 에서 any가 null이면 return 하므로, 아래에서 any?.toString()이 아닌 any.toString()로 호출이 가능하다.
9. 접근 지정자 (Access Modifier)
- public : 모든 곳에서 접근 가능, 접근 지정자를 생략하면 기본적으로 public이 된다.
- internal : 같은 모듈 안에서 접근 가능. (IntelliJ IDEA 모듈, Maven / Gradle 프로젝트 모듈)
- protected : 클래스 내부와, 서브클래스 안에서만 접근 가능.
- private : 프로퍼티와 멤버 함수일 경우, 해당 클래스 안에서만 접근 가능하고, 그 외의 경우, 같은 파일 내에서만 접근 가능하다.
10. 접근 지정자 오버라이딩
오버라이딩을 통해 protected인 프로퍼티나 멤버 함수의 접근 지정자를 public으로 변경할 수 있다.
open class AAA(protected open val number: Int)
class BBB(number: Int) : AAA(number) {
public override val number: Int
get() = super.number
}
fun main(args: Array<String>) {
val b = BBB(26)
val a: AAA = b
println(a.number) // 에러
println(b.number)
}
11. 확장 함수 (Extension Function)
String은 코틀린에 내장된 클래스이기 때문에 원하는대로 멤버 함수를 추가할 수 없다. 이럴 때는 확장 함수를 사용하여, 상속 없이 클래스 외부에서 멤버 함수를 추가할 수 있다. 여기서 함수를 주입할 클래스를 리시버 타입이라고 부른다.
fun String.containNumber(): Boolean { // 문자열에 숫자가 포함되어 있으면 true
this.forEach {
if (it in '0'..'9') return true
}
return false
}
fun main(args: Array<String>) {
println("123abc".containNumber()) // true
println("abc".containNumber()) // false
}
this를 사용하면 리시버 타입의 프로퍼티나 멤버 함수에 접근할 수 있다.
12. 객체 선언
object 키워드를 사용하면 싱글톤 패턴 코드를 더 이상 사용하지 않아도 된다. 프로그램 전체에서 단 하나만 존재하는 객체를 만들 수 있다.
object Person{
var name: String = ""
var age: Int = 0
fun print(){
println("$name $age")
}
}
fun main(args: Array<String>) {
Person.name = "leveloper"
Person.age = 27
Person.print()
}
13. 동반자 객체 (Companion Object)
어떤 클래스의 모든 인스턴스가 공유하는 객체를 만들고 싶을 때 사용한다.
class Person private constructor() {
companion object {
fun create(): Person {
countCreated += 1
return Person()
}
var countCreated = 0
}
}
fun main(args: Array<String>) {
val a = Person.create()
val b = Person.create()
println(Person.countCreated)
}
코틀린에는 static 키워드가 존재하지 않는다. static의 효과를 얻고 싶으면 동반자 객체를 사용해야 한다.
출처 : 초보자를 위한 코틀린 200제 / 엄민석
'Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 문법 정리 - 04 (0) | 2020.04.16 |
---|---|
[Kotlin] 코틀린 문법 정리 - 03 (0) | 2020.04.11 |
[Kotlin] 코틀린 문법 정리 - 01 (0) | 2020.04.03 |
[Kotlin] 코틀린 표준 라이브러리 - 스트림 함수 (0) | 2020.03.28 |
[Kotlin] 안드로이드 스튜디오에서 코틀린 연습하기 (0) | 2020.03.09 |