- 클래스
- 클래스 선언
class User{ }
코틀린에서는 클래스의 생성자를 본문이 아닌 선언부에 작성할 수 있어서 본문이 없는 클래스도 의미가 있다.
- 클래스의 멤버
class User{
var name = "kkang"
constructor(name: String){ //생성자
this.name = name
}
fun someFun(){
println("name : $name")
}
class SomeClass{ }
}
→ 생성자 : constructor라는 키워드로 선언한다.
→ 변수
→ 함수
→ 클래스
- 객체 생성
val user = User("kim")
user.someFun()
객체를 생성할 때는 생성자가 자동으로 호출되므로 소괄호 안에 전달할 매개변수가 클래스에 선언된 생성자의 매개변수와 일치해야 한다.
- 생성자
한 클래스 안에 주 생성자만 선언할 수도 있고 주 생성자와 보조 생성자 둘 다 선언할 수 있다.
- 주 생성자
class User constructor(){ }
→ constructor키워드로 클래스 선언부에 선언 (constructor 키워드 생략 가능)
→ 필수가 아니지만 한 클래스에 하나만 가능
→ 개발자가 생성하지 않으면 컴파일러가 자동으로 매개변수 없는 주 생성자를 생성
class User(name: String, count: Int){
init{
println("i am init...")
}
}
fun main(){
val user= User("kkang",10)
}
→ 주 생성자의 실행 영역에 중괄호 {}를 사용하기 위해서는 init이라는 키워드를 사용한다.
→ init키워드로 지정한 영역은 객체를 생성할 때 자동으로 실행된다.
□ 생성자의 매개변수를 클래스 내부 함수에서 사용 방법
class User(name: String, count: Int){
var name: String
var count: Int
init{
this.count=count
this.name = name
}
fun someFun(){
println("name: $name, count : $count")
}
}
fun main(){
val user= User("kkang",10)
user.someFun()
}
실행결과
name: kkang, count : 10
→ 클래스 내부 함수에서 생성자 매개변수를 사용하기 위해서 클래스 내부에 클래스 멤버 변수를 선언해야 한다.
위 코드와 같은 코드
class User(val name: String, val count: Int){
fun someFun(){
println("name: $name, count : $count")
}
}
fun main(){
val user= User("kkang",10)
user.someFun()
}
실행결과
name: kkang, count : 10
원래 매개변수를 선언할 때 var, val 키워드를 추가할 수 없지만 주 생성자만 유일하게 var, val키워드로 매개변수를 선언할 수 있다.
- 보조 생성자
→ 클래스 본문에 constructor 키워드로 선언
→ 여러 개 추가 가능
class User(){
constructor(매개변수: 반환타입){ ... }
}
- 주 생성자와 보조 생성자 연결
클래스를 선언할 때 둘 중 하나만 선언하면 문제가 없지만, 만약 둘 다 선언한다면 반드시 생성자끼리 연결해주어야 한다.
class User(name: String){
constructor(name:String, count:Int):this(name){
println("countructor(name:String, count:Int) call...")
}
constructor(name:String, count:Int,email:String):this(name,count){
println("constructor(name:String, count:Int,email:String)call...")
}
}
fun main(){
val user1= User("kkang1",10)
val user2 = User("kkang2", 30, "a@a.com")
}
실행결과
countructor(name:String, count:Int) call...
countructor(name:String, count:Int) call...
constructor(name:String, count:Int,email:String)call...
위 코드처럼 주 생성자와 보조 생성자를 선언할 경우 반드시 주 생성자가 실행되게 만들어야 한다.
- 상속
→ 클래스를 선언할 때 다른 클래스를 참조해서 선언하는 것
→ 콜론 ':' 기호를 사용하여 상속한다.
open class Super{ }
class Sub: Super(){ }
→ 상속할 수 있게 상위 클래스에 open키워드를 사용한다.
→ Super를 상속받아 Sub 클래스를 선언한다.
- 상위 클래스 생성자 호출
open class Super(name: String){ }
class Sub(name: String): Super(name){ } //상위클래스 생성자 호출문을 클래스 선언부에 작성
class Sub: Super{ //보조 생성자에서 상위클래스 생성자 호출
constructor(name:String):super(name){ }
}
→ 상위 클래스 생성자를 호출할 때 Super()를 사용한다.
→ 만약 하위 클래스에 보조 생성자만 있다면 보조 생성자에서 super()을 사용한다.
- 오버 라이딩
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()
}
→ 클래스 Super와 클래스 Sub는 서로 상속 관계이다.
→ 위 코드의 Super클래스를 오버 라이딩하였다.
open class Super{
open var superData= 10
open fun superFun(){
println("i am superFun : $superData")
}
}
class Sub:Super(){
override var superData = 20
override fun superFun(){
println("i am sub class function : $superData")
}
}
fun main(){
val obj = Sub()
obj.superFun()
}
→ 오버 라이딩할 때 오버 라이딩할 변수나 함수에 open키워드를 써야 하고 하위 클래스에 override 키워드를 써야 한다.
- 접근 제한자
→ 클래스의 멤버를 외부의 어느 범위까지 이용하게 할 것인지를 결정하는 키워드
→ 코틀린은 4가지 접근 제한자가 있다.
접근 제한자 | 최상위에서 이용 | 클래스 멤버에서 이용 |
public | 모든 파일에서 가능 | 모든 클래스에서 가능 |
internal | 같은 모듈 내에서 가능 | 같은 모듈 내에서 가능 |
protected | 사용 불가 | 상속 관계의 하위클래스에서만 가능 |
private | 파일 내부에서만 가능 | 클래스 내부에서만 가능 |
→ internal : 같은 모듈 내에서 접근할 수 있는데, 모듈이라는 개념은 그래 들(Gradle)이나 메이븐(Maven) 같은 빌드 도구에서 프로젝트 단위 또는 같은 세트 단위를 가리킨다.
- 클래스 종류
- 데이터 클래스
→ data키워드로 선언하며 자주 사용하는 데이터를 객체로 묶어준다.
→ VO(value-object) 클래스를 편리하게 이용할 수 있게 해 준다.
□ 일반 클래스와 데이터 클래스를 비교하는 코드
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 nonData1 = NonDataClass("kkang","a@a.com",10)
val nonData2 = NonDataClass("kkang","a@a.com",10)
val data1 = DataClass("kkang","a@a.com",10)
val data2= DataClass("kkang","a@a.com",10)
println("non data class equals : ${nonData1.equals(nonData2)}")
println("data class equals : ${data1.equals(data2)}")
}
→ 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 data1 = DataClass("kkang","@2@11",10,"1234")
val data2 = DataClass("kkang","@2@11",10,"abcd")
println("data1 & data2 equals : ${data1.equals(data2)}")
}
실행결과
data1 & data2 equals : true
→ 보조 생성자의 멤버 변수는 비교하지 않고 주 생성자 멤버 변수만 비교하여 판단한다.
□ 객체 데이터를 반환하는 toString() 함수
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 nonData = NonDataClass("kkang","a@a.com",10)
val data = DataClass("kkang","a@a.com",10)
println("non data class equals : ${nonData.toString()}")
println("data class equals : ${data.toString()}")
}
실행결과
non data class equals : com.example.androidlab.NonDataClass@6fadae5d
data class equals : DataClass(name=kkang, email=a@a.com, age=10)
→ 일반 클래스 객체의 toString() 함수가 출력하는 값은 의미 있는 데이터가 아니다.
→ 데이터 클래스의 toString() 함수는 객체가 포함하는 멤버 변수의 데이터를 출력한다.
- 오브젝트 클래스
→ 익명 클래스(anonymous class)를 만들 목적으로 사용된다.
→ 이름이 없으므로 선언과 동시에 객체를 생성해야 한다.
→ object라는 키워드를 사용한다.
□ 오브젝트 클래스 사용 예시 1
val obj = object {
var data = 10
fun some() {
println("data : $data")
}
}
fun main() {
obj.data = 20
obj.some()
}
실행결과
Error!
Error!
→ 클래스를 선언하며 객체를 obj변수에 저장하고 obj객체로 클래스에 선언한 멤버에 접근하려 했지만 오류가 난다.
→ object키워드로 클래스를 선언했지만 타입을 명시하지 않아서 이 객체는 최상위 타입인 Any로 취급한다.
→ 오브젝트 클래스의 타입은 object뒤에 콜론 ':'을 입력하고 그 뒤에 상위 클래스 or 인터페이스를 입력한다.
□ 오브젝트 클래스 사용 예시 1
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()
}
실행결과
i am object some : 30
→ 오브젝트 클래스는 Super클래스의 상속을 받는다.
→ obj객체를 이용하여 Super클래스에 선언된 멤버에 접근할 수 있다.
- 컴패니언 클래스
→ 멤버 변수나 함수를 클래스 이름으로 접근하고자 할 때 사용한다.(자바의 static 느낌이다)
→ 객체를 생성하지 않고 클래스 이름으로 특정 멤버를 이용할 수 있다.
→ companion 키워드 사용
□ 컴패니언 클래스의 멤버 접근
class Myclass{
companion object{
var data = 10
fun some(){
println(data)
}
}
}
fun main() {
Myclass.data =20
Myclass.some()
}
실행결과
20
→ companion object {} 형태로 선언하면 클래스 이름으로 접근할 수 있다.
- 람다 함수
많은 프로그래밍 언어에서 제공하는 익명 함수
- 람다 함수 규칙
→ { }로 표현한다
→ { } 안에 화살표(->)가 있고 화살표 왼쪽은 매개변수, 오른쪽은 함수 본문
→ 함수 반환 값은 함수 본문의 마지막 표현식이다
□ 람다 함수 선언 방법
일반 함수
fun sum(num1:Int, num2:Int):Int{
return num1+num2
}
람다 함수
val sum1 = {no1:Int,no2:Int -> no1+no2}
→ fun 키워드를 사용하지 않고 함수 이름도 없다.
□ 람다 함수 호출
sum(10,20)
→ 변수에 대입하여 사용할 수 있다.
□ 람다 함수 선언 및 호출
{no1:Int,no2:Int -> no1+no2}(10,20)
→ 항상 변수에 대입할 필요 없이 바로 호출해서 사용할 수 있다.
- 매개변수 없는 람다 함수
{-> println("function call")}
{println("function call")}
→ 람다 함수에 반드시 매개변수가 있을 필요는 없다.
→ 화살표도 생략 가능하다
- 매개변수가 1개인 람다 함수
val some = { no: Int -> println(no) }
some(10)
val some (Int) -> Unit = {println(it)}
some(10)
실행결과
10
10
→ (Int) -> Unit이 매개변수 1개인 람다 함수임을 알려준다
→ 중괄호 안에 매개변수 선언을 생략하고 println(it)처럼 it키워드로 매개변수를 이용할 수 있다.
- 람다 함수의 반환
→ return 문을 사용할 수 없다.
val some = {no1:Int , no2:Int ->
println("in lambda function")
no1*no2}
println(some(10,20))
→ 마지막 줄의 실행 결과가 람다 함수의 반환 값이다.
'KOTLIN' 카테고리의 다른 글
[Kotlin] 공부 8일차 (2022-01-20) (0) | 2022.01.21 |
---|---|
[Kotlin] 공부 7일차 (2022-01-19) (0) | 2022.01.19 |
[Kotlin] 공부 5일차 (2022-01-17) (0) | 2022.01.18 |
[Kotlin] 공부 4일차 (2022-01-15) (0) | 2022.01.16 |
[Kotlin] 공부 3일차 (2022-01-14) (0) | 2022.01.15 |