국비교육(22-23)

71일차(1)/Android App(15) : Kotlin Abstract Class, Companion, Map

서리/Seori 2023. 1. 17. 23:09

71일차(1)/Android App(15) : Kotlin Abstract Class, Companion, Map

 

 

Stpe05_AbstractClass

package com.example.kotlin_test

//추상 클래스
abstract class Weapon{
    fun move(){
        println("이동합니다.")
    }
    abstract fun attack()
}

class MyWeapon : Weapon(){
    override fun attack() {
        println("무언가를 공격해요")
    }
}

fun main(){
    val w1=MyWeapon()
    w1.move()
    w1.attack()

    println("-------------------")

    /*
        with( 참조값 ){

        }
        참조값을 가지고(참조값과 함께 여러가지 작업을 {} 안에서 한다.

     */
    with(w1){
        move()
        attack()
    }

    //익명 클래스를 이용해서 추상클래스(Weapon) type의 참조값 얻어내기
    val w2= object : Weapon(){//클래스 상속은 ()가 있어야 한다.
        override fun attack() {
            println("공중 공격을 해요")
        }
    }
    w2.move()
    w2.attack()

    //다형성 확인
    val a:MyWeapon = w1
    val b:Weapon = w1
    val c:Any = w1 //java에서 Object type 에 해당되는 type이다.

}

 

- 코틀린에서 추상클래스 만들기!

- 추상클래스에 들어 있는 메소드는 완성되었을 수도 있고 아닐 수도 있다.

 

- 단 미완성된 메소드가 하나라도 있으면

 클래스 앞에 abstract 를 붙여서 추상클래스를 정의해야 한다.

 

- 추상 클래스를 상속하면 추상메소드를 override 하는 것이 강제된다.

- 상속한 클래스에서 추상 메소드를 완성해주면 된다. java와 거의 똑같다!

 

- 담은 변수 w1에 점을 찍어서 그대로 사용할 수 있다.

 

 

** 코틀린의 특이한 문법 : With

 

- 메소드의 설계가 잘 되어있다면 이렇게 연속으로 호출할 수도 있다.

- 이 경우, move() 메소드 안에서 자기 자신의 객체를 다시 리턴해줄 수 있는 구조가 되어야 한다.

 

- 이런 구조이면 자기자신이 리턴되어 메소드를 연속으로 호출할 수 있다.

 

- 자기 자신의 참조값을 다시 리턴하기 때문에 가능한 것

- 이렇게 설계되어 있지 않으면 이렇게 호출할 수 없다. 에러가 난다.

 

- with( ){ } 라는 구문이 있다.

- 그 안에 w1이라는 참조값을 넣어주면 w1에서 사용할 수 있는 메소드를 연속으로 작성해 사용할 수 있다.

- { } 안에서 this 는 MyWeapon 타입이라는 것을 알려주고 있다.

- 그래서 안에서 this.move(), this.attack() 이라고 작성하지 않아도 되는 것이다.(메소드가 매우 많을때 유용하다)

 

- weapon 추상클래스를 상속받은 익명클래스이다.

- 똑같이 밑줄에서 alt+enter로 메소드를 override 해주면 된다.

 

- 클래스 상속은 () 가 있어야 한다.

- 인터페이스를 구현할 때와의 차이!

 

- 코틀린은 java보다 훨씬 더 많은 기능을 제공해주기 때문에,

 코틀린을 사용하면 java보다 적은 코딩양으로 많은 것을 할 수 있다.

- spring boot 에서 작성한 코드도 코틀린으로 변경할 수 있다.

 

 

val / var 식별자 : 타입 = 값 (대입)

- 이런 형태로 작성한다. 타입을 추론할 수 있는 경우에는 생략이 가능하다.

- value에 있는 값이 식별자에 들어간다.

 

- val 상수로 사용: 값이 한번 결정되면 바꾸지 않는다,

- var 변수로 사용: 그때그때 다른 값을 넣어서 사용하겠다.

 


 

val a:MyWeapon = w1
val b:Weapon = w1
val c:Any = w1 //java에서 Object type 에 해당되는 type이다.

 

- w1은 현재 weapon타입의 참조값이 들어가있다.

- 여러 타입에 넣어보면서 다형성 확인하기!

 

val a:MyWeapon = w1
val a = w1

 

- 위와 같이 쓰는 것이 타입을 확실하게 표기하는 것이지만,

  타입을 추론할 수 있으면 아래와 같이 써도 된다.

 

- java의 object (모든타입의 부모타입) 와 같은 것으로

 코틀린에는 Any 라는 타입이있다.

- 어떤 타입의 객체든 모두 Any 타입에 담을 수 있다.

 

 


 

Step06_Companion

package com.example.kotlin_test

class Util{
    //Util 클래스와 함께하는 동반객체
    companion object {
        //동반객체의 필드와 메소드(함수)를 정의하면 된다.
        val version:String="1.1.2"
        fun send(){
            println("전송합니다.")
        }
    }
}

fun main(){
    /*
        클래스명에 . 찍어서 동반객체에 있는 필드나 메소드를 활용할 수 있다.
     */
    Util.send()
    println(Util.version)

}

 

- companio, 동반하는 이라는 뜻!

 

- 위: 참조값 얻어내서 사용하기

- 아래: 클래스에 점 찍어서 사용하기 ← 오류가 발생한다.

 

- java에서는 이것이 구분되었는데, 코틀린에서는 안 된다.

- static 이라는 예약어가 코틀린에는 없다.

 

- 그러면 클래스에 점을 찍어서 바로 사용하는 것은 어떻게 만들면 될까?

 

- Companion object : 동반 객체라는 것이 있다!

- Companion object{ } 안에 메소드를 정의한다.

 

- 이렇게 특이한 모양으로 만드는 이유는? 여러 언어와의 호환성을 위해서

- 이렇게 작성해두면 아래에서 Util.send() 형태로 작성할 수 있다.

 

- 클래스명에 . 점을 찍어서 동반 객체에 있는 필드나 메소드를 활용할 수 있다.

- 클래스가 하나만 만들어지는 java에서의 static 클래스/메소드와 비슷한 것이다.

- companion object{} 이 중괄호 안에 정의하면 된다.

 

 

- 필드도 정의할 수 있고,

 필드 또한 클래스명에 점을 찍어서 바로 사용할 수 있다.

 


 

Step07_Map

package com.example.kotlin_test

fun main(){
    //수정 불가능한 Map
    val mem=mapOf<String, Any>("num" to 1, "name" to "바나나", "isMan" to false)

    //Map 에 저장된 데이터 참조하는 방법1
    val num=mem.get("num")
    val name=mem.get("name")
    val isMan=mem.get("isMan")

    //Map 에 저장된 데이터 참조하는 방법2
    val num2=mem["num"]
    val name2=mem["name"]
    val isMan2=mem["isMan"]

    //수정 가능한 Map
    val mem2= mutableMapOf<String, Any>()
    //빈 Map에 데이터 넣기 방법1
    mem2.put("num",2)
    mem2.put("name","딸기")
    mem2.put("isMan", true)

    val mem3:MutableMap<String,Any> = mutableMapOf()
    //빈 Map에 데이터 넣기 방법2
    mem3["num"]=3
    mem3["name"]="복숭아"
    mem3["isMan"]=false
}

 

- java의 HashMap 사용법

 

- 코틀린에서 java 클래스를 import해서사용할 수 있을까?

 

- 클래스를 import 하려고 보면 java.util 이 있다??!

- 이외에도 java의 ArrayList 등도 사용할 수 있다.

- 코틀린은 java와 100% 호환되기 때문에 java에 있는 클래스를 가져다 쓸 수 있다.

 

- HashMap도 두가지 버전이 있다.

 

- 코틀린에서 HashMap<>() 과 비슷한 메소드로는 mapOf<>() 라는 메소드가있다.

 

- key : value 가 아니라 key to value 로 작성한다.

 

//Map 에 저장된 데이터 참조하는 방법1
val num=mem.get("num")
val name=mem.get("name")
val isMan=mem.get("isMan")

//Map 에 저장된 데이터 참조하는 방법2
val num2=mem["num"]
val name2=mem["name"]
val isMan2=mem["isMan"]

1) 변수명.get("데이터")

2) 변수명["데이터"]

- 데이터를 참조하여 가져오는 방법이 2가지가 있다.

 

mapOf<>()

- mapOf 는 수정 불가능한 Map이다. 데이터가 한번 들어가면 상수처럼 사용해야 한다.

- 제네릭을 굳이 쓰자면...? 안에 들어있는 타입 종류가 여러개이므로 Any로 받아주어야 한다.

- 근데 key, value의 타입을 모두 추론(infer)할 수 있기 때문에 굳이 작성 안해줘도 된다. 생략가능!

 

mutableMapOf<>()

- 수정가능한 맵 

- .put() 으로 새로 넣어주기 가능

 

- <> 제너릭 타입을 지정하는 것은 메소드에다가 넣을 수도 있고, 변수를 받을 때 지정할 수도 있다.

 (당연 위의 방법이 더 편하다!)