클래스와 생성자
클래스 선언
class user{ }
클래스 멤버는 생성자, 변수, 함수, 클래스로 구성됩니다.
생성자 키워드: constructor
class User {
var name = "kkang"
constructor(name: String){
this.name = name
}
fun someFun(){
println("name: $name")
}
class SomeClass{ }
}
위 클래스 생성자를 아래와 같이 작성할 수도 있다.
class User(val name: String)
이러면 본문 없는 클래스라도, 생성자까지 이미 정의된 것이다.
클래스는 객체를 생성해서 사용하고 그 객체로 멤버에 접근합니다.
코틀린에서는 객체를 new를 사용하지 않고 아래와 같이 생성 합니다.
val user = User("kim")
user.someFun()
객체 생성 시 생성자가 자동으로 호추되므로 소괄호 안에 전달한 인자는 클래스 생성자 매개인자와 맞아야 합니다.
주 생성자
코틀린 클래스 생성자는 주 생성자와 보조 생성자로 구분합니다.
주 생성자는 constructor 키워드로 클래스 선언부에 선언합니다.
class User contructor(){
}
주 생성자 선언은 필수는 아니고, 한 클래스에 하나만 가능합니다.
주 생성자의 constructor를 생략할 수 있습니다.
주 생성자를 선언하지 않으면 컴파일러가 매개변수 없는 주 생성자를 자동으로 추가합니다.
class User(){
}
주 생성자 매개변수
주 생성자 선언 시 매개변수를 선언할 수도 있습니다. 괄호에 바로 매개인자를 선언했습니다.
class User(name: String, count: Int){
}
위와 같이 선언했으면 클래스 생성할 때 매개변수를 넣어줍니다.
val user = User("구턴", 10)
주 생성자 본문 - init
코틀린 클래스 안에서 init 키워드로 지정한 영역은 객체를 생성할 때 자동으로 실행됩니다.
class User(name: String, count: Int){
init{
println("I am init...")
}
}
fun main(){
val user = User("9tun", 10)
}
I am init...
생성자 매개변수를 클래스 멤버 변수로 선언
생성자에서 사용한 매개변수를 클래스 멤버 변수로 쓰려면 아래와 같이 해야 합니다.
class User(name: String, count: Int){
// 클래스 멤버 변수 선언
var name: String
var count: Int
init{
// 클래스 멤버 변수에 생성자 매개변수 대입
this.name = name
this.count = count
}
fun someFun(){
println("name: $name, count: $count")
}
}
fun main(){
val user = User("9tun", 10)
user.someFun()
}
위 방법보다 더 간단히 하는 법:
class User(val name: String, val count: Int){
fun someFun(){
println("name: $name, count: $count")
}
}
fun main(){
val user = User("9tun", 10)
user.someFun()
}
보시면 애초에 class 매개인자 자리에 "val"을 사용한 것을 볼 수 있습니다.
보조 생성자
클래스 본문에 constructor 키워드로 선언하는 생성자 함수입니다.
본문에 선언하므로 여러 번 선언할 수 있습니다.
class User {
constructor (name: String){
println("constructor(name: String) call...")
}
constructor (name: String, count: Int){
println("constructor(name: String, count: Int) call...")
}
}
fun main(){
val user1 = User("9tun")
val user2 = User("9tun", 10)
}
보조 생성자에 주 생성자 연결
클래스에 주 생성자와 보조 생성자를 모두 선언하면, 보조 생성자에서 주 생성자를 호출해 줘야 합니다.
claa User(name: String){
constructor(name: String, count: Int): this(name){
}
}
fun main(){
val user = User("9tun", 10)
}
보조 생성자 선언부에 this(name)을 추가했습니다.
이렇게 하면 보조 생성자로 객체를 생성할 때 주 생성자가 함께 호출됩니다.
주 생성자 + 여러 개의 보조 생성자를 선언한 경우, 보조 생성자에서 this()로 다른 보조 생성자를 호출할 수 있습니다.
이때에도 어떤 식으로든 주 생성자를 호출해야 합니다.
claa User(name: String){
constructor(name: String, count: Int): this(name){
}
constructor(name: String, count: Int, email: String): this(name, count){
}
}
fun main(){
val user = User("9tun", 10, "9tun@daum.net")
}
매개인자가 3개인 보조 생성자를 호출하면,
→ this(name, count)를 통해서 매개인자가 2개인 보조 생성자가 호출되고,
→ 매개인자 2개인 보조 생성자가 호출되면,
→ 다시 this(name)을 통해서 주 생성자가 호출된다.
클래스 상속
상속과 생성자
open class Super{ // 상속할 수 있게 open 키워드 사용
}
class Sub: Super(){ // Super를 상속받아 Sub 클래스 선언
}
✅ 상위 클래스
상속 대상이 되는 클래스
✅ 하위 클래스
상속 받는 클래스
✅ 상속 가능 키워드
코틀린 클래스는 기본적으로 다른 클래스를 상속할 수 없습니다.
다른 클래스에서 상속할 수 있게 선언하려면 open 키워드를 사용합니다.
open class Super(name: String){
}
class Sub(name: String): Super(name){
}
오버라이딩
open class Super{
var superData = 10
fun superFun(){
println("I am superFun: $superData")
}
}
class Sub:Super()
fun main(){
val obj = Sub()
obj.superData = 20
obj.superFun()
}
때로 상위 클래스에 정의된 멤버를 하위 클래스에서 재정의해야 할 수도 잇습니다.
✅ 오버라이딩
상위 클래스에 선언된 변수나 함수를 같은 이름으로 하위 클래스에서 다시 선언하는 것
같은 함수명으로 하위 클래스에서 새로운 로직을 추가하고 싶을 때 오버라이딩을 사용합니다.
open class Super{
open var someData = 10
open fun someFun(){
println("I am super class function: $someData")
}
}
class Sub: Super(){
override var someData = 20
override fun someFun(){
println("I am sub class function : $someData")
}
}
fun main(){
val obj = Sub()
obj.someFun()
}
👨🏫 코틀린의 오버라이딩 규칙
오버라이딩 허용할 변수나 함수 선언 앞에 open 키워드를 추가
📌 C++에서는 Virtual이란 키워드가 해당 역할을 했었음
접근 제한자
클래스 멤버를 외부 어느 범위까지 이용하게 할지 결정하는 키워드
접근 제한자 | 최상위에서 이용 | 클래스 멤버에서 이용 |
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(){
val obj = Super()
obj.publicData++ // 성공
obj.protectedData++ // 실패
obj.privatedData++ // 실패
}
코틀린 클래스 종류
데이터 클래스
키워드 data로 선언, 자주 사용하는 데이터를 객체로 묶어줍니다.
// 일반 클래스
class NonDataClass(val name:String, val email:String, val age:Int)
// 데이터 클래스
data class DataClass(val name:String, val email:String, val age: Int)
// 일반 클래스와 데이터 클래스를 비교하귀 위해 같은 인자를 전달해 객체를 2개씩 생성
fun main(){
val non1 = NonDataClass("9tun", "9tun@daum.net", 45)
val non2 = NonDataClass("9tun", "9tun@daum.net", 45)
val data1 = DataClass("9tun", "9tun@daum.net", 45)
val data2 = DataClass("9tun", "9tun@daum.net", 45)
}
객체 데이터 비교: equals()
println("non data class equals: ${non1.equals(non2)}")
println("data class equals: ${data1.equals(data2)}")
non data class equals: false
data class equals: true
일반 클래스 객체 non1은 equals로 data를 비교할 수 없다.
데이터 클래스 객체 data1은 equals로 data 비교가 가능하다.
📌 equals() 함수는 주 생성자에 선언한 멤버 변수의 데이터만 비교 대상으로 삼는다.
data class DataClass(val name:String, var 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("9tun", "9tun@daum.net", 45, "Seoul")
val obj2 = DataClass("9tun", "9tun@daum.net", 45, "Busan")
println("obj1.equals(obj2): ${obj1.equals(obj2)}")
}
obj1.equals(obj2): true
👨🏫 주 생성자의 멤버 변수값이 같기 때문에 true 라고 나옵니다.
객체 데이터 반환: toString()
fun main(){
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("9tun", "9tun@daum.net", 45)
val data = DataClass("9tun", "9tun@daum.net", 45)
println("non data class toString: ${non.toString()}")
println("data class toString: ${data.toString()}")
}
non data class toString: com.example.androidlab.P122Kt$main$NonDataClass@37a71e93
data class toString: DataClass(name=9tun, email=9tun@daum.net, age=45)
일반 클래스의 toString 출력값은 의미있는 데이터가 아닙니다.
데이터 클래스의 toString 출력값은 객체가 포함하는 멤버 변수의 데이터 출력합니다.
📌 toString() 함수도 주 생성자의 매개변수에 선언된 데이터만 출력 대상입니다.
오브젝트 클래스
이름없는 클래스, 즉 익명 클래스 생성에 사용합니다.
클래스 선언과 동시에 객체를 생성한다는 의미에서 object 키워드를 사용합니다.
val obj = object{
var data = 10
fun some() {
println("data: ${data})
}
}
fun main() {
obj.data = 20 // 오류
obj.some() // 오류
}
object 키워드로 클래스를 선언했지만, 타입을 명시하지 않았으므로, 최상위 타입인 any로 취급됐다.
하지만 any 객체에는 data나 some()이라는 멤버가 없기 때문에 오류가 발생한 것이다.
따라서 클래스 타입 object 뒤에 클래스의 상위 클래스/인터페이스를 입력해야 합니다.
그럼 그 상위 클래스 타입으로 이용할 수 있는 것이다.
open class Super{
open var data = 10
open fun some(){
println("I am super some(): $data")
}
}
val obj = object: Super(){
override var data = 20
override fun some(){
println("I am object some(): $data")
}
}
fun main(){
obj.data = 30 // 성공
obj.some() // 성공
}
컴패니언 클래스
멤버 변수나 함수를 클래스 이름으로 접근할 때 사용합니다.
일반적으로 클래스 멤버는 객체를 통해 접근해야 합니다. 하지만 컴패니언 클래스는 객체 생성 없이 접근 가능합니다.
class MyClass{
var data = 10
fun some(){
println(data)
}
}
fun main(){
val obj = MyClass()
obj.data = 20 // 성공, 객체를 통해 접근
obj.some() // 성공, 객체를 통해 접근
MyClass.data = 20 // 오류, 클래스 이름으로 접근할 수 없음
MyClass.some() // 오류, 클래스 이름으로 접근할 수 없음
}
위와 같이 클래스 이름으로 접근이 불가한 것을 컴패니언 클래스로 접근해 보자.
class MyClass{
companion object{
var data = 10
fun some(){
println(data)
}
}
}
fun main(){
MyClass.data = 20 // 성공, 클래스 이름으로 접근
MyClass.some() // 성공, 클래스 이름으로 접근
}
📌 C++의 정적(static) 멤버처럼 동작하는 객체입니다.

끝
'Android' 카테고리의 다른 글
뷰를 이용한 화면 구성 (0) | 2025.06.13 |
---|---|
코틀린 유용한 기법 (0) | 2025.06.09 |
고틀린 (0) | 2025.06.01 |
안드로이드 앱 기본 구조 (0) | 2025.05.30 |
개발 환경 준비 (0) | 2025.05.27 |