[Android Studio] 4장 - 코틀린 문법 정리 (3)

이상협·2022년 9월 3일
2

클래스 선언

class User {
	var name = "gildong"
    constructor(name: String) {
    	this.name = name
    }
    fun some() {
    	...
    }
    class SomeClass { }
}

constructor는 코틀린의 생성자

주 생성자

  • 코틀린 생성자는 주 생성자보조 생성자로 구분
class User constructor() { ... }
class User() { ... }                         // constructor 생략 가능
class User { ... }                           // 주 생성자가 없으면 자동으로 매개변수 없는 주생성자 생성
class User(name: String, count: Int) { ... } // 주 생성자의 매개변수

주 생성자의 본문 - init

class User(name: String, count: Int) {
	init {
    	println(" init ")
    }
}

생성자의 매개변수를 클래스의 멤버 변수로 선언

class User(name: String, count: Int) {
	init {
    	println("name : $name, count : $count") // 성공
    }
    fun some() {
    	println("name : $name, count : $count") // 오류
    }
}

생성자의 매개변수는 지역변수로, 다른 함수에서는 사용 불가능

class User(name: String, count: Int) {
	var name: String
    var count: Int
    init {
    	this.name = name
        this.count = count
    }
}

클래스 멤버 변수 선언해주면 매개변수 사용이 가능

class User(val name: String, val count: Int) {
	fun some() {
    	println(" ,,, ")
    }
}

주 생성자에서만 유일하게 var이나 val 키워드로 매개변수를 선언 할 수 있음


보조 생성자

  • 클래스의 본문에 constructor 키워드로 선언하는 함수
  • 여러개 추가 가능

보조 생성자에 주 생성자 연결

class User(name: String) {
	constructor(name: String, count: Int) { // 오류
    	...
    }
}

주 생성자가 있으면 보조 생성자에서 주 생성자를 호출 해줘야함

class User(name: String) {
	constructor(name: String, count: Int): this(name) {
    	...
    }
}

보조 생성자 선언부에 this(name)만 추가하면 주 생성자가 호출됨

보조 생성자가 여러개일 경우

class User(name: String) {
    constructor(name: String, count: Int): this(name) {
        ...
    }
    constructor(name: String, count: Int, email: String): this(name, count) {
        ...
    }
}

위와 같이 그 위의 보조 생성자를 다시 불러오면 됨


상속과 생성자

클래스 상속 형식

open class Super { // 상속할 수 있게 open 키워드 이용
}
class Sub: Super() { // Super를 상속받아 Sub 클래스 선언
}

매개변수가 있는 상위 클래스의 생성자 호출

open class Super(name: String) {
}

/* 1 */
class Sub(name: String): Super(name) {
}

/* 2 */
class Sub: Super {
	constructor(name: String): super(name) {
    }
}

하위 클래스의 보조 생성자가 있다면 클래스 선언부에 꼭 생성자 호출문을 작성할 필요는 없음


오버라이딩 - 재정의

  • 상위 클래스에 선언된 변수나 함수를 같은 이름으로 하위 클래스에서 다시 선언하는 것
open class Super {
	open var data = 10
    open fun some() {
    	println(" ... ")
    }
}
class Sub: Super() {
	override var data = 20
    override var some() {
    	println("$data")
    }
}

open 키워드를 선언하지 않으면 하위 클래스에서 재정의 할 수 없음


접근 제한자

  • 클래스의 멤버를 외부의 어느 범위까지 이용하게 할 것인지를 결정
  • public, internal, protected, private 가 있음
접근 제한자최상위에서 이용클래스 멤버에서 이용
public모든 파일에서 가능모든 클래스에서 가능
internal같은 모듈 내에서 가능같은 모듈 내에서 가능
protected사용 불가상속 관계의 하위 클래스에서만 가능
private파일 내부에서만 이용클래스 내부에서만 이용
open class Super {
	var publicData = 10
    protected var protectedData = 20
    private var privateData = 30
}

class Sub: super() {
	fun subFun() {
    	publicData++    // 성공
        protectedData++ // 성공
        privateData++   // 오류
    }
}

fun main() {
	var obj = Super()
    obj.publicData++    // 성공
    obj.protectedData++ // 오류
    obj.protectedData++ // 오류
}

데이터 클래스

class NonDataClass(val name: String, val email: String, val age: Int)
data class DataClass(val name: String, val email: String, val age: Int)

data키워드를 이용해 자주 사용하는 데이터를 객체로 묶어 줌

equals() - 데이터 객체 비교 함수

val non1 = NonDataClass("gildong", "aaa@a.com", 10)
val non2 = NonDataClass("gildong", "aaa@a.com", 10)

val data1 = DataClass("gildong", "aaa@a.com", 10)
val data2 = DataClass("gildong", "aaa@a.com", 10)

non1.equals(non2)    // false
data1.equals(data2)  // true

위 처럼 data 클래스를 이용하면 객체의 데이터를 비교할때 편리
하지만, equals()를 사용한 데이터 비교는 주 생성자에서 선언한 멤버 변수의 데이터만 비교 대상으로 삼음

data class DataClass(val name: String, val email: String, val age: Int) {
	lateinit var address: String
    constructor(name: String, email: String, age: Int, address: String): this(name. email, age) {
    	this.address = address
    }
}

fun main() {
	val obj1 = DataClass("gildong", "aaa@a.com", 10, "seoul")
    val obj2 = DataClass("gildong", "aaa@a.com", 10, "busan")
    obj1.equals(obj2) // true
}

이처럼 equals()는 주 생성자의 멤버 변수가 같은지만 판단함

toString()

class NonDataClass(val name: String, val email: String, val age: Int)
data class DataClass(val name: String, val email: String, val age: Int)

val non = NonDataClass("gildong", "aaa@a.com", 10)
val data = DataClass("gildong", "aaa@a.com", 10)

non.toString()  // com.example.androidlab.....
data.toString() // DataClass(name=gildong, email=aaa@a.com, age=10)

이 처럼 데이터 클래스의 toString() 함수는 객체가 포함하는 멤버 변수의 데이터를 출력

오브젝트 클래스

  • 익명 클래스를 목적으로 사용
  • 클래스 이름이 없으므로 선언 동시에 객체를 생성해야함
  • object 라는 키워드 사용
val obj = object {
	var data = 10
    fun some() {
    	println("...")
    }
}

fun main() {
	obj.data = 20 // 오류
    obj.some()    // 오류
}

오브젝트 클래스를 선언했지만 그 안의 변수나 함수를 사용하는데에는 오류가 발생함. 그 이유로는 타입을 명시하지 않아 Any로 취급이 되는데,
Any타입에는 선언한 변수나 함수들이 없기 때문에 오류가 발생하는 것임

open class Super {
	open var data = 10
    open fun some() {
    	println("$data")
    }
}

val obj = object: Super() {
	override var data = 20
    override fun some() {
    	println("$data")
    }
}

fun main() {
	obj.data = 30 // 성공
    obj.some()    // 성공
}

Super 클래스를 상속 받았기 때문에 클래스 내에 선언된 멤버에 접근이 가능하게 됨

컴패니언 클래스

  • 멤버 변수나 함수를 클래스 이름으로 접근하고자 할 때 사용
  • 객체를 생성하지 않고서도 클래스 이름으로 특정 멤버 이용 가능
class MyClass {
	companion object {
    	var data = 10
        fun some() {
        	println(data)
        }
    }
}

fun main() {
	MyClass.data = 20  // 성공
    MyClass.some()     // 성공
}

클래스 내부에서 companion object {} 형태로 선언하게 되면 클래스 이름으로 멤버에 접근 가능


참고

Do it! 깡쌤의 안드로이드 프로그래밍 with 코틀린 (개정판)

0개의 댓글