이 글은 Android12 및 코틀린 완전 정복를 참고하여 작성하였습니다.
작성자 : 정호영
개발환경은 Windows, Android Studio입니다.
1. 접근제어자
public : 접근제어자를 표시하지 않을 시 기본 값. 누구나 접근이 가능하다.
private : 파일 안(해당 클래스) 안에서만 접근이 가능하다.
internal : 프로젝트의 모듈안에서는 누구나 접근이 가능하다.
protected : 최상위에 정의되는 클래스로 인터페이스에서는 사용할 수 없다.
Scope : public > protected / internal > private
++ 모듈이란 프로젝트 바로 아래의 개념으로 패키지와 클래스를 포함한다.
open class Outer {
private val a = 1
protected open val b = 2
internal open val c = 3
val d = 4 // public by default
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {
// a is not visible
// b, c and d are visible
// Nested and e are visible
override val b = 5 // 'b' is protected
override val c = 7 // 'c' is internal
}
class Unrelated(o: Outer) {
// o.a, o.b are not visible
// o.c and o.d are visible (same module)
// Outer.Nested is not visible, and Nested::e is not visible either
}
2. 중첩 및 내부 클래스
자바의 경우 A 클래스안에서 B 클래스를 정의하면 B 클래스는 자동으로 A의 내부클래스가 되었지만 코틀린에서는 아님.
A 클래스 안에 B 클래스를 정의하면 기본적으로 중첩 클래스가 되지만 B 클래스를 내부 클래스로 만들고 싶다면 inner 키워드로 클래스를 선언한다.
inner 클래스는 기본적으로 외부 클래스를 참조하여 객체에 접근하지만 중첩 클래스는 그렇지 않다.
class Outer {
private val bar: Int = 1
class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
fun main() {
print(demo)
}
이 경우를 출력해보면 Unresolved reference: bar 에러가 발생한다.
중첩된 클래스에 inner 키워드를 붙여주면
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
fun main() {
print(demo)
}
demo 는 1이 출력된다.
interface OuterInterface {
class InnerClass
interface InnerInterface
}
class OuterClass {
class InnerClass
interface InnerInterface
}
인터페이스, 클래스는 여러개의 인터페이스, 클래스를 중첩클래스로 가질 수 있다.
3. Null Safety
첫 주 차 Nullable 에 배웠던 내용과 더해져 다양한 Null 방지 방법이 있다.
1. 조건에서 Null 확인
val l = if (b != null) b.length else -1
2. Safe Call 사용
person?.department?.head = managersPool.getManager()
처음으로 person이 널인가체크 후 department가 널인지 체크한다.
var a = "코틀린"
val b: String? = null
println(b?.length)
println(a?.length) // Unnecessary safe call
위의 경우 Null 일 경우 Null 을 출력하지만 Null 이 아닐 경우만 출력하고 싶을 수 있다. 그럴땐 let 호출 연산자를 사용한다.
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints Kotlin and ignores null
}
3. 엘비스 연산자
?: 을 기준으로 왼쪽은 널이 아닐때의 값과 오른쪽은 널일 경우 디폴트 값이다.
// if-else
val l: Int = if (b != null) b.length else -1
// Elvis Operator
val l = b?.length ?: -1
4. Safe Cast
Int 값을 String 으로 파싱하지 않고 강제로 Casting 해버리면 ClassCastException 이 발생한다.
이를 방지하기 위해서 as? 를 지원한다.
val a1 = "1"
val a1Int: Int? = a1 as? Int // a1Int = null;
val a2 = 1
val a2Int: Int? = a2 as? Int // a2Int = 1;
4. 예외 처리
1. Throw
fun main() {
val maxAge = 150
if(maxAge !in 0..100) {
throw IllegalArgumentException("최대 나이는 100살입니다.")
}
else {
print(maxAge)
}
}
Exception in thread "main" java.lang.IllegalArgumentException: 최대 나이는 100살입니다.
at com.professionalandriod.apps.kotlinbasics.BasicsKt.main(Basics.kt:8)
at com.professionalandriod.apps.kotlinbasics.BasicsKt.main(Basics.kt)
자바와의 차이점은 throw가 식이므로 new 키워드를 사용하지 않아도 된다는 점이다.
2.
fun main() {
try {
val tempNum = "100"
val tempIntNum = tempNum as Int
val divideNum = 100 / 0;
} catch (e: ArithmeticException) {
println(e)
} catch (e : ClassCastException) {
println(e)
}
finally {
print("여기는 항상 실행된다.")
}
}
try 문 하나에도 여러개의 catch문이 대응될 수 있으며, finally는 오류가 발생하던 안하던 항상 실행된다.
위 경우는 터미널 출력은 아래와 같이 나왔다.
java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
(java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
여기는 항상 실행된다.
try를 기준으로 2번째 줄에서 String을 Int로 변환 할 수 없기에 에러가 발생하였고 catch로 잡아 내었다.
테스트 결과 에러가 발생되면 두번째 에러는 실행되지 않고 finally 코드를 출력하고 종료되는 것을 알 수 있다.
'GDSC HUFS 4기 > Kotlin Team #3' 카테고리의 다른 글
[3팀] Android-12-Kotlin : 코틀린 계산기 - XML사용법과 UI생성법 배우기 (Onclick-OnOperator) (0) | 2022.11.03 |
---|---|
[3팀] Android-12-Kotlin : 코틀린 기초 더 배우기(배열 - 람다식) (0) | 2022.10.09 |
[3팀] Android-12-kotlin : OOP, Class, 섀도잉 (0) | 2022.10.07 |
[3팀] Android-12-kotlin Interface and Abstract class (1) | 2022.10.07 |
[3팀] Android-12-Kotlin: Conditions and Loops (0) | 2022.10.03 |