Kotlin/StoreInfo

<강의> Kotlin 문법 종합반 3주차

re트 2023. 11. 28. 15:17
728x90

1. 메소드 설계

  - 특별한 로직을 가지는 소스코드에 이름을 붙일 수 있고 이름이 붙은 소스코드는 메소드라고 부름

  - Kotlin의 메소드 기본 구조

fun 메소드이름(변수명:자료형, 변수명:자료형 ....): 반환자료형 {
		소스코드 로직
}

  - 메소드를 사용하는 이유

    1) 로직을 추상화하여 상황에 맞기 쓰기 위해서

    2) 코드의 재사용성을 높이기 위해서

  - 예시

fun main() {
    var myMathScore = readLine()!!.toInt()
    // 매개변수로 사용자에게 입력받은 myMathScore 값을 넘겨줌
    var myRank = checkRank(myMathScore)
    println("나의 등급은 : ${myRank}")
}

fun checkRank(score:Int): String { // 반환자료형이 없을 때는 Unit을 쓰거나 생략하면 됨
		return when(score) {
			in 90..100 ->	return "A"
			in 80..89 -> return "B"
			in 70..79 -> return "C"
			else -> return "D"
		}
        
//    Kotlin 컨벤션을 따르지 않은 형태
//    if(score >= 90) {
//        return "A"
//    } else if(score >= 80) {
//        return "B"
//    } else if(score >= 70) {
//        return "C"
//    } else {
//        return "D"
//    }
}

  <출력결과>

98
나의 등급은 : A
========================
50
나의 등급은 : D

 

2. 클래스 설계

  - 객체지향 프로그래밍(OOP: Object Oriented Programming)

    1) Kotlin의 모든 것은 클래스 형태이므로 객체화 가능

    2) 프로그램에서 필요한 데이터를 추상화시켜 상태와 행위를 객체 생성

    3) 객체들간의 적절한 결합을 통해 유지보수를 쉽게 함

  - 객체지향 프로그래밍의 5대 키워드

    1) 클래스

    2) 추상화

    3) 캡슐화

    4) 상속

    5) 다형성

  - 클래스(= 프로그램의 각 요소별 설계도)

  - Kotlin에서는 class 키워드를 활용하여 클래스 생성

  - 클래스에는 정보(프로퍼티)와 행위(메소드)를 작성

  - 하나의 파일 안에 여러개의 클래스가 존재할 수 있음

  - Kotlin의 클래스 구조

class 클래스이름 {
    정보1
    정보2

    행위1
    행위2
}

  - 특별한 클래스

    1) 데이터 클래스(data class) : 정보만 가지고 있는 클래스

      - 아주 유용한 메소드를 자동으로 생성

        [1] hashCode() : 객체를 구분하기 위한 고유값 리턴

        [2] equals() : 동일한 객체인지 비교해서 true 또는 false 리턴

        [3] copy() : 현재 객체의 모든 정보를 복사해서 새로운 객체 리턴

        [4] toString() : 현재 객체의 모든 정보를 예쁘게 출력

        [5] getXXX()/setXXX(매개변수) : 변수의 값을 리턴/설정

      - 예시

data class 클래스이름 {
    정보1
    정보2
}

    2) 실드 클래스(sealed class) : 상속받을 수 있는 자식클래스들을 미리 정의하는 클래스

      - 클래스 상속과 관련된 개념

      - 무분별한 상속 방지

      - 컴파일 시점에 생성할 수 있는 자식을 알 수 있기 때문에 효율적으로 다형성을 구현 가능

      - 예시

sealed class 부모클래스 {
    class 자식클래스1 : 부모클래스생성자
    class 자식클래스2 : 부모클래스생성자
}

    3) 오브젝트 클래스(object class) : 프로그램을 실행하는 동시에 인스턴스화하는 클래스

      - Java의 static 대신 사용하는 키워드

    4) 열거 클래스(enum class) : 상수값에 대한 관리 지점을 최소화할 수 있는 클래스

      - Comparable 인터페이스를 구현하는 추상 클래스

      - 예시

enum class 클래스1 {
    C, JAVA, KOTLIN
}

enum class 클래스2(val code: Int) {
    C(10),
    JAVA(20),
    KOTLIN(30)
}

fun main() {
    println(클래스1.C.toString()) // 출력: C
    println(클래스2.KOTLIN.code) // 출력: 30
    println(클래스2.KOTLIN.name) // 출력: KOTLIN
}

 

3. 생성자의 활용

  - 기본 생성자와 명시적 생성자가 존재

  - 명시적 생성자는 주 생성자와 부 생성자로 구분 가능

  - 한 가지 형태로 클래스를 실체화할 때는 주 생성자를 활용하고 여러 형태로 실체화할 때는 부 생성자를 활용가능

  - Init(주 생성자)의 사용 예시

// 매개변수를 직접 넘기지않음
init {
    println("매개변수없는 생성자 실행 완료!")
}

  - Constructor(부 생성자)의 사용 예시

// 명시적 생성자 (Constructor)
// _name, _hairColor, _height와 같이 생성자에 변수를 넘기는 경우에 사용함
constructor(_name:String, _hairColor:String, _height:Double) {
    println("${_name}을 생성자로 넘겼어요")
    println("${_hairColor}를 생성자로 넘겼어요")
    println("${_height}를 생성자로 넘겼어요")
}

 

4. 객체의 활용

  - 객체 : 모든 인스턴스를 포함하는 개념, 클래스 타입으로 선언된 것들

  - 클래스 형태로 설계된 객체를 실체화하면 인스턴스가 생기고 인스턴스는 메모리 공간을 차지

  - 클래스를 실체화해서 위치정보를 메모리에 적재하여 프로그램을 로딩

  - 프로그램은 객체의 위치정보를 변수에 저장해두고, 필요할 때 참조

  - 예시

fun main() {
    // 불마법사로 객체화
    var magicianOne = Character("불마법사", "red", 180.2)

    // 냉마법사로 객체화
    var magicianTwo = Character("냉마법사", "blue", 162.2, 25, "여")
}

 

5. 상속

  - 클래스 간의 관계를 더욱 단단하게 만듬

  - 공통적인 요소들을 부모/자식 클래스로 구분해서 상속관계로 만듬

  - Kotlin은 무분별한 상속으로 예상치 못한 흐름을 방지하기 위해 생략된 final 키워드로 상속을 막아두었기 때문에 open 키워드를 활용해서 상속 관계를 만들 수 있음

  - 상속을 사용하는 이유

    1) 다형성 구현

    2) 클래스의 내용 변경 필요시 부모 클래스만 변경 가능

  - 예시

fun main() {
    var bird = Bird("새")
    var chicken = Chicken("닭")
    var sparrow = Sparrow("참새")
    var pigeon = Pigeon("비둘기")

    bird.fly()
    chicken.fly()
    sparrow.fly()
    pigeon.fly()
}
// 부모 클래스에서 생성자를 활용하는 경우에는 자식에서 객체 생성 시 생성자까지 전달해줘야함
open class Bird(name:String) {
    var name: String = ""

    init {
        // this는 현재 클래스의 상태변수를 의미합니다
        // var name: String = ""
        this.name = name
    }

    fun fly() {
        println("${name} 날아요~")
    }

}

class Chicken(name: String) : Bird(name) {

}

class Sparrow(name: String) : Bird(name) {

}

class Pigeon(name: String) : Bird(name) {

}

  <출력결과>

새 날아요~
닭 날아요~
참새 날아요~
비둘기 날아요~

 

6. 오버라이딩

  - 상속받은 부모 클래스의 정보나 행위를 재설계하는 것

  - 주로 부모 클래스의 행위를 재설계함

  - 공통적인 내용을 부모 클래스에서 관리하지만, 자식 클래스의 개성을 살리고 싶을 때 사용

  - 예시

fun main() {
    var bird = Bird("새")
    var chicken = Chicken("닭", 2)
    var sparrow = Sparrow("참새", "갈색")
    var pigeon = Pigeon("비둘기", "서울")

    bird.fly()
    chicken.fly()
    sparrow.fly()
    pigeon.fly()
}

open class Bird(name:String) {
    var name: String = ""

    init {
        // this는 현재 클래스의 상태변수를 의미합니다
        // var name: String = ""
        this.name = name
    }
    // open 키워드를 붙여줘야 오버라이딩 가능
    open fun fly() {
        println("${name}는 날아요~")
    }

}

class Chicken(name: String, age: Int) : Bird(name) {
    var age:Int = 0

    init {
        this.age = age
    }

    override fun fly() {
        // super객체는 부모의 객체를 의미하며 자동으로 생성됨
        // 즉 부모객체의 fly메소드를 부르는 행위임
        // 필요없으니 주석처리완료
        // super.fly()
        println("${age}살의 ${name}이 날아봅니다~ 꼬끼오!")
    }
}

class Sparrow(name: String, color: String) : Bird(name) {
    var color:String = ""

    init {
        this.color = color
    }

    override fun fly() {
        println("${color}의 ${name}가 날아봅니다~ 짹짹!")
    }
}

class Pigeon(name: String, address: String) : Bird(name) {
    var address: String = ""

    init {
        this.address = address
    }

    override fun fly() {
        println("${address} 살고있는 ${name}가 날아봅니다~ 구구!")
    }
}

  <출력결과>

새는 날아요~
2살의 닭이 날아봅니다~ 꼬끼오!
갈색의 참새가 날아봅니다~ 짹짹!
서울 살고있는 비둘기가 날아봅니다~ 구구!

 

7. 오버로딩

  - 매개변수의 갯수나 자료형을 다르게 하고 동일한 이름으로 메소드를 만드는 것

  - 반환형은 오버로딩에 영향을 주지 않음

  - 예시

fun main() {
    var calc = Calculator()
    
    var intResult = calc.add(1,2)
    var doubleResult = calc.add(1.2, 2.2)
    
    println("정수 덧셈결과: ${intResult}")
    println("실수 덧셈결과: ${doubleResult}")
    
}

class Calculator {
    
    fun add(num1: Int, num2: Int): Int {
        return num1+num2
    }
    
    fun add(num1: Double, num2: Double): Double {
        return num1+num2
    }
}

  <출력 결과>

정수 덧셈결과: 3
실수 덧셈결과: 3.4000000000000004

 

8. 인터페이스

  - Kotlin은 부모클래스를 하나만 상속받을 수 있어서 근본적인 공통점은 상속받고, 추가적인 기능들을 인터페이스로 추가

  - Kotlin은 인터페이스를 만들기 위해 interface 키워드를 사용

  - Kotlin의 인터페이스 구조

interface 인터페이스이름 {
    fun 메소드이름() // 추상 메소드
}

  - 예시

fun main() {
    var bird = Bird("새")
    var chicken = Chicken("닭")
    var sparrow = Sparrow("참새")
    var pigeon = Pigeon("비둘기")
    var duck = Duck("오리")

    bird.fly()
    chicken.fly()
    sparrow.fly()
    pigeon.fly()
    duck.swim()
}

open class Bird(name:String) {
    var name: String = ""

    init {
        this.name = name
    }

    fun fly() {
        println("${name} 날아요~")
    }

}

class Chicken(name: String) : Bird(name) {

}

class Sparrow(name: String) : Bird(name) {

}

class Pigeon(name: String) : Bird(name) {

}

class Duck(name: String) : Bird(name), WaterBirdBehavior {
    override fun swim() {
        println("${name}가 수영해요~")
    }
}

interface WaterBirdBehavior {
    fun swim()
}

  <출력 결과>

새 날아요~
닭 날아요~
참새 날아요~
비둘기 날아요~
오리가 수영해요~

 

반응형