[새싹] 현대IT&E 240111 기록 - Kotlin

최정윤·2024년 1월 11일
0

새싹

목록 보기
51/67
post-custom-banner

2.5 클래스

2.5.1 클래스 선언 및 객체 생성

class Car(val color : String)
val car = Car("red")    // 객체 생성
println("My car color is ${car.color}") // 객체의 color 프로퍼티 사용

2.5.2 클래스 생성자

주 생성자

class Person1 constructor(name : String) {}
class Person2(name : String) {}
class Person3(val name : String) {}

보조 생성자

class Person4 {
    constructor(age : Int) {
        println("I'm $age years old")
    }
}

class Person5(name : String) {
    constructor(name : String, age : Int) : this(name) {
        println("I'm $age years old")
    }
}

초기화 블록

class Person6(name : String) {
    val name : String
    init {
        if (name.isEmpty()) {   // 문자열이 비어 있는 걍우 에러 발생
            throw IllegalArgumentException("이름이 없어요.")
        }
        this.name = name    // 문자열이 안 비어 있으면 이름 저장
    }
}
val newPerson = Person6("") // 에러 발생
val newPerson = Person6("yeon-seo") // 객체 생성 성공

2.5.3 클래스의 상속

open class Flower {
    open fun waterFlower() {
        println("water flower")
    }
}
class Rose : Flower() {
    override fun waterFlower() {
        super.waterFlower() // Flower 클래스의 메서드 먼저 실행
        println("Rose is happy now")
    }
}
val rose = Rose()   // 객체 생성
rose.waterFlower()  // water flower; Rose is happy now

open class Flower(val name : String) {}
class Rose(name : String, color : String) : Flower(name) {}

2.5.4 접근 제한자

private val b = 2

2.5.5 컴패니언 객체: companion 키워드

class Dinner{
    companion object{   // object 키워드
        val MENU = "pasta"  // 정적 변수 생성
        fun eatDinner() {
            println("$MENU is yummy!")
        }
    }
}

println(Dinner.Companion.MENU)  // pasta
println(Dinner.MENU)    // Companion 생략 가능 -> pasta
Dinner.eatDinner()  // pasta is yummy!

2.5.6 추상 클래스

abstract class Game {
    fun startGame() {
        println("게임을 시작했습니다.")
    }
    
    // 추상 메서드
    abstract fun printName()
}

class Overwatch : Game() {
    override fun printName() { // 추상 메서드 구현
        println("오버워치입니다.")
    }
}

val overwatch = Overwatch()
overwatch.startGame() // Game 클래스 메서드 -> 게임을 시작했습니다.
overwatch.printName() // Overwatch 클래스에서 구현한 메서드 -> 오버워치입니다.

2.5.7 데이터 클래스

data class Memo(val title : String, val content: String, var isDone:Boolean)
var memo1 = Memo("마트 가기", "계란, 우유, 빵", false)

data class Memo(val title: String, val content: String, var isDone: Boolean)
var memo1 = Momo("마트가기", "계란, 우유, 빵", false)
var memo2 = memo1.copy(content = "칫솔, 과자") // content 프로퍼티만 변경

println(memo1.toString())
// Memo(title=마트 가기, content=계란, 우유, 빵, isDone=false)

println(memo2.toString())
// Memo(title=마트 가기, content=칫솔, 과자, isDone=false)

2.6 인터페이스

2.6.1 인터페이스 정의

interface Car{
    abstract fun drive()
    fun stop() // abstract 생략 가능
}

2.6.2 디폴트 메서드

interface Car{
    abstract fun drive()
    fun stop() // abstract 생략 가능
    fun destroy() = println("차가 파괴되었습니다.")
}

2.6.3 인터페이스 구현

class Ferrari: Car {
    
}

class Ferrari : Car {
    override fun drive() {
        println("페라리가 달립니다.")
    }
    
    override fun stop() {
        println("페라리가 멈춥니다.")
    }
}

val myFerrari = Ferrari()   // 객체 생성

myFerrari.drive()   // 페라리가 달립니다.
myFerrari.stop()    // 페라리가 멈춥니다.
myFerrari.destroy() // Car 인터페이스 디폴트 메서드 -> 차가 파괴되었습니다.

2.6.4 다중 인터페이스 구현

interface Animal {
    fun breath()
    fun eat()
}

interface Human {
    fun think()
}

class Korean : Animal, Human { // 2개 이상의 인터페이스 구현
    override fun breath() {
        println("후-하 후-하")
    }
    override fun eat() {
        println("한식 먹기")
    }
    override fun think() {
        println("생각하기")
    }
}

2.6.5 클래스 상속과 인터페이스 구현

interface Animal {
    fun breath()
    fun eat()
}

interface Human {
    fun think()
}

open class Name(val name : String) {
    fun printName() {
        println("제 이름은 $name")
    }
}

class Korean(name : String) : Name(name), Animal, Human {
    override fun breath() {
        println("후-하 후-하")
    }
    override fun eat() {
        println("한식 먹기")
    }
    override fun think() {
        println("생각하기")
    }
}

val joyce = Korean("정아")
joyce.breath()
joyce.printName()

2.7 Null 처리하기

2.7.1 Nullable과 Non-Nullable

var myName : String

var myName : String = null

var myName : String? = null

var myName : String? = null
myName = "Joyce"
println(myName.reversed()) // 에러 발생

2.7.2 셰이프 콜 연산자?

fun reverseName(name : String?) : String? {
    return name?.reversed()
}

println(reverseName("joyce"))
println(reverseName(null))

2.7.3 엘비스 연산자 ?:

fun reverseName(name : String?) : String {
    return name?.reversed() ?: "이름을 확인해주세요."
}

println(reverseName("joyce"))
println(reverseName(null))

2.7.4 확정 연산자 !!

fun reverseName(name : String?) : String { // 반환 자료형은 null 불가능
    return name!!.reversed() // 절대 null이 아님을 보증
}

println(reverseName("joyce")) // ecyoj

println(reverseName(null)) // 에러 발생. java.lang.NullPointerException

2.7.5 lateinit 키워드와 lazy 키워드

lateinit 키워드

lateinit var lunch : String
lunch = "waffle"

println(lunch)

lazy 키워드

val lazyBear : String by lazy{
    println("곰이 일어났습니다.")
    "bear"
}

println(lazyBear) // lazy 블록 실행됨
println(lazyBear) // 이미 초기화되었으므로 블록 실행 안됨

2.8 람다식

val sayHello = fun() { println("안녕하세요.") }
sayHello()  // 안녕하세요.

2.8.1 람다식 정의

val squareNum : (Int) -> (Int) = { number -> number*number }
println(squareNum(12)) // 144

val squareNum2 = {number : Int -> number*number}

val squareNum3 : (Int) -> Int = {it*it}

2.8.2 람다를 표현하는 다양한 방법

fun invokeLambda(labmda : (Int) -> Boolean) : Boolean {
    return lambda(5)
}

val paramLambda : (Int) -> Boolean = {num -> num == 10}

println(invokeLambda(paramLambda))

invokeLambda({num -> num == 10}) // 람다식 바로 넣어주기
invokeLambda({it == 10}) // 인수가 하나일 때 it으로 변경 가능
invokeLambda() {it == 10} // 만약 하수의 마지막 인수가 람다일 경우 밖으로 뺄 수 있음
invokeLambda{it == 10} // 그 외 인수가 없을 때 () 생략 가능

2.8.3 SAM 변환

button.setOnClickListener{
    // 버튼이 눌렸을 때 작동할 코드
}

public ovid setOnClickListener(@Nullable OnClickListener l) {
    ...
}

public interface OnClickListener {
    void onClick(View v);
}

// 람다를 사용하지 않았을 때
button.setOnClickListener(object : OnClickListener{
    override fun onClick(view: View) {
        doSomething()
    }
})

// 람다 사용 1
button.setOnClickListener({ view -> doSomething() })

// 람다 사용 2 : 코틀린 컴파일러가 인수를 미리 알기 때문에 생략,
// (인수가 여러 개일 때) 마지막 인수가 람다인 경우 {}를 밖으로 이동
button.setOnClickListener() { doSomething() }

// 람다 사용 3 : 유일한 인수인 경우 () 생략
button.setOnClickListener { doSomething() }

Kotlin Docs 바로가기 ▶️


NOXMLActivity.kt

package com.example.helloworld

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet

class NoXMLActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ConstraintLayout 생성
        val layout = ConstraintLayout(this).apply {
            layoutParams = ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
            id = ConstraintSet.PARENT_ID
        }

        // 버튼 생성
        val button = Button(this).apply {
            id = View.generateViewId()
            text = "클릭하세요"
            layoutParams = ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.WRAP_CONTENT,
                ConstraintLayout.LayoutParams.WRAP_CONTENT
            )
            setOnClickListener {
                Toast.makeText(this@NoXMLActivity, "안녕하세요", Toast.LENGTH_SHORT).show()
                //Toast.makeText(applicationContext, "안녕하세요", Toast.LENGTH_SHORT).show()
            }
        }

        // 레이아웃에 버튼 추가
        layout.addView(button)

        // 버튼을 레이아웃 중앙에 배치
        ConstraintSet().apply {
            clone(layout)
            connect(button.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0)
            connect(button.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0)
            connect(button.id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 0)
            connect(button.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0)
            applyTo(layout)
        }

        // 생성된 레이아웃을 액티비티의 콘텐츠 뷰로 설정
        setContentView(layout)
    }
}
profile
개발 기록장
post-custom-banner

0개의 댓글