접근제한자
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 입니다.
라고 나옴.