📕클래스
💡클래스의 기본적인 형태
class 키워드 다음에 클래스 이름이 오고 그다음에 본문이 오는 형태로 구성된다.
클래스 본문에는 멤버 정의가 들어있다.
class Person{
var firstName = " "
var familyName= " "
var age =0
fun fullname()= "$firstName $familyName"
fun showMe(){
println("${fullname()} : $age")
}
}
위 클래스 정의는 모든 Person 클래스의 인스턴스마다 firstName, familyName, age라는 프로퍼티
와, fullname(), showMe()라는 두 함수
가 들어있음을 알려준다.
모든 프로퍼티에서 일반적으로 쓸 수 있는 기능에는 다음과 같이 마치 변수처럼 프로퍼티를 사용하는 참조 구문이 있다.
fun showAge(p:Person) = println(p.age) //프로퍼티(age)에 읽기
fun readAge(p:Person){
p.age=readLine()!!.toInt() //프로퍼티(age)에 쓰기
}
프로퍼티는 어떤 클래스의 구체적인 인스턴스(위 코드에는 p)와 엮여 있기 때문에 이 인스턴스를 식으로 지정해야 한다.
이런 인스턴스(p)를 수신 객체(receiver)
라 부르고, 수신 객체는 프로퍼티에 접근할 때 사용하는 객체를 지정한다.
멤버 함수의 경우에도 똑같이 수신 객체가 있고, 이런 경우 멤버 함수를 메서드(method)
라 부른다
fun showFullName(p: Person) = println(p.fullname()) //메서드 호출하기
클래스 내부에서는 this 식으로 수신 객체를 참조할 수 있다.
대부분의 경우 this를 디폴트로 가정하기 때문에 수신 객체의 멤버 안에서 수신 객체의 멤버를 참조할 때는 this를 생략해도 된다.
class Person{
var firstName = " "
var familyName= " "
var age =0
fun fullname()= "${this.firstName{ ${this.familyName}"
fun showMe(){
println("${this.fullname()} : ${this.age}")
}
}
🛑this가 꼭 필요한 경우!
클래스의 프로퍼티 이름과 메서드의 파라미터 이름이 같은 경우 둘을 구분하기 위하여 프로퍼티 이름 앞에 this를 써야 한다.
class Person{
var firstName = " "
var familyName= " "
var age =0
fun setName(firstName : String, familyName:String){
this.firstName=firstName
this.familyName=familyName
}
}
📕생성자
클래스 인스턴스를 초기화해주고 인스턴스 생성 시 호출되는 특별한 함수
class Person(firstName:String, familyName: String){
val fullName="$firstName $familyName"
}
class 키워드 이름 뒤에 파라미터는 클래스의 인스턴스를 생성할 때 클래스에 전달된다.
이 파라미터를 이용해 프로퍼티를 초기화하고 다른 일을 수행할 수 있다.
fun main(){
val person=Person("Jaehan","Lee") //새로운 Person 인스턴스 생성
println(person.fullName) //Jaehan Lee
}
코틀린에서는 생성자를 호출할 때 (자바의 new와 같은) 특별한 키워드를 사용하지 않는다.
클래스 헤더의 파라미터 목록을 주생성자 선언
이라고 부른다.
주생성자는주생 성자는 함수와 달리 본문이 하나가 아니다. 대신 주생 성자는 클래스 정의 내에서 프로퍼티 초기화와 초기화 블록이 등장하는 순서대로 구성된다.
[프로퍼티 초기화 -> init 블록이 등장해야한다]
❌순서가 바뀐다면 오류가 발생!❌
💻초기화 블록
init이라는 키워드 앞에 붙은 블록이며 이 블록 안에서 느 클래스 초기화 시 필요한 간단하지 않은 초기화 로직을 수행할 수 있다. [ 단 초기화 블록 안에는 return 문이 들어가지 못한다.]
그리고 init 블록 안에서 프로퍼티를 초기화하는 것도 허용된다.
import java.util.*
import kotlin.*
import java.lang.*
class Person(fullName: String){
val firstName: String
val familyName: String
init{
val names = fullName.split(" ")
if(names.size!=2){
throw java.lang.IllegalArgumentException("Invalid name: $fullName")
}
firstName=names[0]
familyName=names[1]
}
val FullName="$firstName $familyName"
}
fun main(){
val person=Person("Leejae Han")
println(person.FullName)
}
위 코드에서 init 블록은 fullName을 공백으로 분리 후 문자열의 배열로 나눈 다음 firstName과 familyName 프로퍼티를 각각 초기화한다.
- 컴파일러는 모든 프로퍼티가 확실히 초기화되는지 확인한다.
- 만약 확실하게 초기화되지 않았다면 컴파일 오류가 발생한다.
- 확실하게 초기화시켜주기 위해서는 예외처리를 시켜줘야 한다.
-❌주생 성자 파라미터를 프로퍼티 초기화나 init 블록 밖에서 사용할 수는 없다.
class Person(firstName:String,familyName:String){
val fullName="$firstName $familyName"
fun printName() {
println(firstName)
}
}
멤버 함수 내부에서는 firstName을 사용할 수 없기 때문에 위 코드는 잘못된 코드이다.
이에 대한 해법으로는 생성자 파라미터(firstName)의 값을 저장할 멤버 프로퍼티를 정의하는 것이다.
class Person(firstName:String,familyName:String){
val fullName="$firstName $familyName"
val firstName=firstName
fun printName() {
println(firstName) //생성자 파라미터를 가르킴
}
}
이것보다 더 간단한 방법이 있다.
import java.util.*
import kotlin.*
import java.lang.*
class Person(val firstName:String,val familyName:String){
val fullName="$firstName $familyName"
//val firstName=firstName
fun printName() {
println(firstName+familyName)
}
}
fun main(){
val person=Person("Leejae","Han")
person.printName()
}
💡생성자 파라미터 앞에 val이나 var 키워드를 붙여준다.
자동으로 해당 생성자 파라미터로 초기화되는 프로퍼티를 정의한다.(여기서 프로퍼티는 생성자 파라미터와 이름이 같다)
💡val/var 파라미터를 사용하면 본문이 비어있는 클래스를 정의할 수 있다.
class Person(val firstName:String, val familyName:String =" "){
}
💡디폴트 값과 vararg를 생성자 파라미터에 사용한 경우
import java.util.*
import kotlin.*
import java.lang.*
class Person(val firstName : String, val familyName: String=" "){
fun fullName()="$firstName $familyName"
}
class Room(vararg val persons :Person ){
fun showNames(){
for(person in persons ) println(person.fullName())
}
}
fun main(){
val room=Room(Person("John"),Person("Jane","Smith")) //John Jane Smith
room.showNames()
}
여러 생성자를 사용해 클래스 인스턴스를 서로 다른 방법으로 초기화하고 싶을 때 주생 성자만으로는 충분하지 않은 경우 부생 성자를 사용해 해결할 수 있다.
부생성자
함수 이름 대신에 constructor 키워드를 사용한다는 점을 제외하면 함수 정의 문법과 비슷하다.
부생 성자에 반환타입은 본적으로 Unit 타입 값을 반환한다.[ 반환 타입을 지정할 수는 없음]
그리고 inti 블록과 달리 부생성자 안에서는 return을 사용할 수 있다.
부생 성자의 파라미터 목록에는 val/var 키워드를 사용할 수 없다.
constructor(firstName : String, familyName : String){
this.firstName= firstName
this.familyName= familyName
}
정리
'Skils > Kotlin' 카테고리의 다른 글
[Kotlin] 널 가능성 (0) | 2022.09.01 |
---|---|
[Kotlin] 멤버 가시성, 내포된 클래스(inner), 지역 클래스 (0) | 2022.08.30 |
[Kotlin] 예외 처리 (0) | 2022.08.27 |
[Kotlin] break & continue, 내포된 루프와 레이블 (0) | 2022.08.17 |
[Kotlin] 반복문 while, do-while, for (0) | 2022.08.17 |