코틀린 클래스
- -
클래스 선언
class User{ }
- 클래스의 멤버
class User {
var name ="google"
constructor(name: String) {
this.name = name
}
fun someFun() {
println("name : $name")
}
class SomeClass { }
}
코틀린의 생성자는 constructor라는 키워드로 선언하는 함수
- 객체 생성과 멤버 접근
val user = User("goo") //객체를 생성하는 코드
user.someFun()
객체를 생성할 때 생성자가 자동으로 호출되므로 소괄호 안에 전달한 인자는 클래스에 선언된 생성장자의 매개변수와 들어맞아야 한다. 앞에서 작성한 User크래스의 생성자는 constructor(name:google)이므로 문자열 데이터를 전달받는 매개변수가 있습니다.
주 생성자
- 주 생성자 선언
class User constructor() {
}
주 생성자는 constructor 키워드로 클래스 선언부에 선언한다.
주 생성자의 매개변수
- 주 생성자의 매개변수
class User(name: String, count: Int) {
}
앞에 코드는 User클래스를 선언하면서 주 생성자에 매개변수를 2개 선언했다.
- 매개변수가 있는 생성자 호출
val user = User("kkang", 10)
객체를 생성할 때 매개변수의 타입과 개수에 맞는 인자를 전달해야 한다.
- init 키워드로 주 생성자의 본문 지정
class User(name: String, count: Int) {
init {
println("i am init....")
}
}
fun main() {
val user = User("google", 10)
}
User라는 클래스에 주 생성자를 선언하고 클래스 본문에 init 여역을 두어 주 생성자의 본문을 작성했습니다.
이렇게 하면 main()함수에서 User 클래스의 객체를 생성할 때 init 영역에 작성한 코드가 자동으로 실행됩니다.
생성자의 매개변수를 클래스의 멤버 변수로 선언하는 방법
- 생성자의 매개변수를 init 영역에서 사용하는 예
class User(name: String, count: Int) {
init {
println("name: $name, count : $count") //성공!
}
fun someFun() {
println("name : $name, count : $count") //오류!
}
}
생성자를 호출할때 init 영역이 실행되므로 이곳에서 생성자의 매개변수에 접근할수 있다.
but, 생성자의 매개변수는 지역 변수이므로 다른 함수에서는 사용할 수 없습니다.
- 생성자의 매개변수를 다른 함수에서 사용하는 예
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("google", 10)
user.someFun()
}
- 생성자의 매개변수를 클래스의 멤버 변수로 선언하는 방법
class User(val name: String, val count: Int) {
fun someFun() {
println("name : $name, count : $count") //성공!
}
}
fun main() {
val user = User("google", 10)
user.someFun()
}
주 생성자에서만 유일하게 var나 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("google")
val user2 = User("google", 10)
}
보조 생성자에 주 생성자 연결
주 생성자와 보조 생성자를 모두 선언한다면 반드시 생성자끼리 연결해 주어야 한다.
- 주 생성자와 보조 생성자 선언 시 오류
class User(name: String) {
constructor(name: String, count: Int) { //오류!
(..생략..)
}
}
- 보조 생성자에서 주 생성자 호출
class User(name: String) {
constructor(name: String, count: Int): this(name) { //성공!
//생략
}
}
fun main() {
val user = User("google", 10)
}
- 보조 생성자가 여럿일 때 생성자 연결
class 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("google, 10, "a@a.com")
}
클래스를 재사용하는 상속
상속과 생성자
- 클래스 상속 형식
open class Super { //상속 할수 있는 open 키워드 이용
}
class Sub: Super() { //Super를 상속받아 Sub 클래스 선언
}
클래스를 선언할 때 다른 클래스를 참조해서 선언하는 것을 상속inheritance라고 한다.
코틀린에서 어떤 클래스를 상속받으려면 선언부에 코론(:)과 함께 상속받을 클래스 이름을 입력 합니다.
- 매개변수가 있는 상위 클래스의 생성자 호출
open class Super(name: String) {
}
class Sub(name: String): Super(name) {
}
- 하위 클래스에 보조 생성자만 있는 경우 상위 클래스의 생성자 호출
open class Super(name: String) {
}
class sub: Super {
constructor(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()
}
상위 클래스에 정의된 멤버(변수, 함수)를 하위 클래스에서 자신의 멤버처럼 사용할수 있다.
main함수에서 Sub클래스의 객체를 생성한 후 이 객체를 이용해 superData와 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 키워드를 추가하는 것입니다.
그리고 open 키워드로 선언한 변수나 함수를 하위 클래스에서 재정의 할 때는 반드시 선언문 앞에 override라는 키워드를 추가해야 한다.
접근 제한자
클래스의 멤버를 외부의 어느 범위까지 이용하게 할 것인지를 결정하는 키워드 입니다.
접근 제한자 | 최상위에서 이용 | 클래스 멤버에서 이용 |
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.privateData++ //오류!
}
코들린의 클래스 종류
- 데이터 클래스 선언
class NonDataClass(val name: String, val email: String, val age: Int)
data class DataClass(val name: String, val email: String, val age: Int)
- 데이터 클래스 객체 생성
fun main() {
val non1 = NonDataClass("google", "a@a.com", 10)
val non2 = NonDataClass("google", "a@a.com", 10)
val data1 = DataClass("google", "a@a.com", 10)
val data2 = DataClass("google", "a@a.com", 10)
}
객체의 데이터를 비교하는 equals()함수
- 객체의 데이터를 비교하는 equals()함수
println("non data class equals : ${non1.equals(non2)}") //결과값: false
println("data class equals : ${data1.equals(data2)}") //결과값: true
- 데이터 클래스의 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("google", "a@a.com", 10, "seoul")
val obj2 = DataClass("google", "a@a.com", 10, "busan")
println("obj1.equals(obj2) : ${obj1.equals(obj2)}")
}
데이터 클래스의 equals() 함수는 주 생성자의 멤버 변수가 같은지만 판단 합니다.
- 데이터 클래스의 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("google", "a@a.com", 10)
val data = DataClass("google", "a@a.com", 10)
println("non data class toString : ${non.toString()}")
println("data class toString : ${data.toString()}")
}
실행결과
non data class toString : com.example.test4.ch2.Test2Kt$main$NonDataClass@61bbe9ba
data class toString : DataClass(name=google, email=a@a.com, age=10)
오브젝트 클래스
오브젝트 클래스는 익명 클래스 를 만들 목적으로 사용
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() //오류!
}
MyClass의 객체를 생성 한 후 객체명으로 멤버에 접근하는 데는 문제가 없다.
- 캠피니언 클래스의 멤버 접근
class MyClass {
companion object {
var data = 10
fun some() {
println(data)
}
}
}
fun main() {
MyClass.data = 20 //성공!
MyClass.some() //성공!
}
클래스의 내부에 companion objcet { } 형태로 선언하면 이 클래스를 감싸는 클래스 이름위 소스에서는 MyClass으로 멤버에 접근한다.
소중한 공감 감사합니다