본문 바로가기

카테고리 없음

23.12.06코틀린

접근제한자

public: 명시하지 않으면 기본적으로 public

private: 동일한 클래스 내부에서만 접근가능

internal: 같은 모듈 내부에서만 접근

protected: 기본적으로 private이지만 상속을 받은경우에 타 모듈에서 접근가능

 

쓰는 이유는 무분별한 접근금지, 클래스들이 접근하면 안되는거 막을수 있음. 아마도 네가 클래스 asdf를 쓸 때 다른 파일에서 작업할 때 asdf쓰면 충돌하고 먹통되는데 그걸 막을수 있는 모양이다.

class AccessTestClass {
    public var a:Int = 1
    var b = 2
    private var c = 3
    internal var d = 4
    protected var e = 5

    public fun publicTest() {
        println("public 입니다")
    }

    fun publicTest2() {
        println("public 입니다")
    }

    private fun privateTest() {
        println("private 입니다")
    }

    internal fun internalTest() {
        println("internal 입니다")
    }

    protected fun protectedTest() {
        println("protected 입니다")
    }
}

이러면 public은 어짜피 의미 없으니 다 쓸수있고  

private이건 같은 클래스만 쓸수 있어서 여기선 c를 사용할수 있으나 다른 파일을 만들면 거기선 c를 못씀

internal은 모듈에서만 사용 가능하니 모듈안이면 새 파일을 만들어도 d는 사용가능 
protected는 같은 클래스거나 상속받으면 사용 가능이니 여기서 쓰거나 하위 클래스를 만들어서 사용가능

 

 try {
        예외가 발생할 가능성이 존재하는 코드
    } catch(예외종류) {
        예외가 발생했을때 처리할 코드
    }
}

이걸 트라이 캐치라고 함

fun method1(num1:Int) {
    if(num1 > 10) {
        throw 예외종류
    }
}

이건 throw 이건 말그대로 예외의 종류 앞에 throw 넣기

 

만약 숫자를 입력해야 하는데 문자를 입력했다면?

fun main() {
    while(true) {
        try {
            var num1 = readLine()!!.toInt()
            println("내가 입력한 숫자는 ${num1}입니다")
            break
        } catch(e:java.lang.NumberFormatException) {
            println("숫자를 입력하세요")
        }
    }
}

이러면 숫자 입력할때까지 무한루프 돌려서 해결

 

다른 방법: finally를 추가

 

fun main() {
    while(true) {
        try {
            var num1 = readLine()!!.toInt()
            println("내가 입력한 숫자는 ${num1}입니다")
            break
        } catch(e:java.lang.NumberFormatException) {
            println("숫자를 입력하세요")
        } finally {
            println("키보드와의 연결은 정상적입니다")
        }
    }
}

 

숫자를 입력하세요
키보드와의 연결은 정상적입니다 라는 메시지로 옳은 답 유도

 

지연초기화

코틀린은 클래스를 설계할 때 안정성을 위해 반드시 변수의 값을 초기화할것을 권장하는데, 클래스를 설계할 때 초기의 값을 정의하기 난처해서 나중에 대입하기 위한 문법. 변수는  lateinit, 상수는 lazy를 사용

 

예시

fun main(){
    var s1 = Student()
    s1.name = "참새"
    s1.displayInfo()

    s1.age = 10
    s1.displayInfo()
}

class Student {
    lateinit var name:String
    var age:Int = 0

    fun displayInfo() {
        println("이름은: ${name} 입니다.")
        println("나이는: ${age} 입니다.")
    }
}

이러면 이렇게 나옴

 

이름은: 참새 입니다.
나이는: 0 입니다.
이름은: 참새 입니다.
나이는: 10 입니다.

 

그 이유는 lateinit 때문에 나이는 0이 먼저 나온뒤에 초기화 되어 위의 나이는 10이 출력되는것

 

고급사용법

fun main(){
    var s1 = Student()
    s1.name = "참새"
    s1.displayInfo()

    s1.age = 10
    s1.displayInfo()
}

class Student {
    lateinit var name:String
    var age:Int = 0

    fun displayInfo() {
        if(this::name.isInitialized) {
            println("이름은: ${name} 입니다.")
            println("나이는: ${age} 입니다.")
        } else {
            println("name변수를 초기화해주세요.")
        }
    }
}

 

이건 진짜로 초기화가 되는건지 확인하는 방법으로, this::name.isInitialized를 넣어야 안정적이 된다고 한다. 별차이 없는거 같지만...

 

상수초기화

fun main(){
    var s1 = Student()
    s1.name = "참새"
    s1.displayInfo()

    s1.age = 10
    s1.displayInfo()
}

class Student {
    lateinit var name:String
    var age:Int = 0
    val address: String by lazy {
        println("address 초기화")
        "seoul"
    }

    fun displayInfo() {
        println("이름은: ${name} 입니다.")
        println("나이는: ${age} 입니다.")
        println("주소는: ${address} 입니다.")
    }
}

 

상수초기화는 상수가 출력되는 순간에 사용됨. 여기선 주소에 상수초기화인 lazy를 사용.

이걸 실행하면, 먼저 아까처럼 참새, 0 이나오고 어드레스 초기화가 적용. 그 뒤에 서울이 출력되고 초기화

 

그래서 다음엔 참새, 10살, 서울 즉,

 

이름은: 참새 입니다.
나이는: 0 입니다.
address 초기화
주소는: seoul 입니다.
이름은: 참새 입니다.
나이는: 10 입니다.
주소는: seoul 입니다. 

라고 나옴.