JAVA 를 베이스로 한 코틀린을 예시코드 통해 학습 해봅시다!
● 클래스 다형성
콜라 인스턴스를 음료 인스턴스에 담는 행위를 상위 자료형인 수퍼클래스로 변환한다고 하여 Up-Casting
Up-Casting을 다시 하위 자료형으로 변환하면 Down-Casting
fun main() {
var a = Drink()
a.drink()
// 콜라 인스턴스를 음료 인스턴스에 담는 행위를
// 상위 자료형인 수퍼클래스로 변환한다고 하여
// Up-Casting 이라고 함!
var b : Drink = Cola()
b.drink()
// Up-Casting을 다시 하위 자료형으로 변환하면 Down-Casting 이라고 함
// is 는 호환되는 자료형을 변환해주지만 조건문 내에서만 동작
if(b is Cola){
b.wachDishes()
}
// as 는 호환되는 자료형으로 변환해주는 캐스팅 연산자
// 변환된 자료형을 반환까지 함
var c = b as Cola
c.wachDishes()
// b가 되는 이유는 c에서 as로 이미 변환했기 때문에
b.wachDishes()
}
// 클래스 다형성
open class Drink(){
var name = "음료"
open fun drink(){
println("${name} 를 마십니다")
}
}
class Cola : Drink(){
var type = "콜라"
override fun drink(){
println("${name} 중에 ${type} 를 마십니다")
}
fun wachDishes(){
println("${type} 로 설거지를 합니다")
}
}
● Generic 함수
제네릭 함수/클래스는 타입을 미리 고정하지 않고, 호출 시 결정되는 타입을 그대로 가져와 사용하게 해주는 문법
fun main() {
UsingGeneric(A()).doShouting()
UsingGeneric(B()).doShouting()
UsingGeneric(C()).doShouting()
}
fun <T : A> doShouting(t:T){
t.shout()
}
open class A {
open fun shout(){
println("A가 소리칩니다.")
}
}
class B : A(){
override fun shout(){
println("B가 소리칩니다.")
}
}
class C : A(){
override fun shout(){
println("C가 소리칩니다.")
}
}
class UsingGeneric<T : A> (val t : T){
fun doShouting(){
t.shout()
}
}
● 내부클래스
inner 클래스는 outer 클래스의 변수를 참조 가능
outer 클래스를 참조할 때에는 this@Outer 를 사용
fun main() {
Outer.Nested().introduce()
val outer = Outer()
val inner = outer.Inner()
inner.introduceInner()
inner.introduceOuter()
outer.text = "Changed Outer Class"
inner.introduceOuter()
}
class Outer{
var text = "Outer Class"
class Nested{
fun introduce(){
println("안녕")
}
}
// inner 클래스는 outer 클래스의 변수를 참조 가능
inner class Inner{
var text = "Inner Class"
fun introduceInner(){
println(text)
}
// outer 클래스를 참조할 때에는 this@Outer 를 사용
fun introduceOuter(){
println(this@Outer.text)
}
}
}
● data 클래스
data 클래스는 데이터를 처리하기에 더욱 용이한 클래스!
아래의 코드를 수행했을 때 값의 차이를 확인할 수 있다
fun main() {
val a = General("보영",212)
println(a == General("보영",212))
println(a.hashCode())
println(a)
val b = Data("루다",306)
println(b == Data("루다",306))
println(b.hashCode())
println(b)
println(b.copy())
println(b.copy("아린"))
println(b.copy(id=316))
// 리스트 형식으로도 열거할 수 있음
val list = listOf(Data("보영",212),
Data("루다",306),
Data("아린",316)
)
for((a, b) in list){
println("${a} , ${b}")
}
}
class General(val name:String, val id:Int)
data class Data(val name:String, val id:Int)
● enum 클래스
enum 은 선언시 만든 객체를 이름으로 참조하여 그대로 사용
fun main() {
// enum 은 선언시 만든 객체를 이름으로 참조하여 그대로 사용
var state = State.SING
println(state)
state = State.SLEEP
println(state.isSleeping())
state = State.EAT
println(state.message)
}
enum class State(val message:String){
SING("노래를 부릅니다"),
EAT("밥을 먹습니다"),
SLEEP("잠");
fun isSleeping() = this == State.SLEEP
}
● Map 셋팅
Map 으로 key, value 를 저장하여 데이터를 가져오고 변경, 삭제가 가능
fun main() {
val a = mutableMapOf("레드벨벳" to "음파음파",
"트와이스" to "FANCY",
"ITZY" to "ICY")
for (entry in a){
println("${entry.key} : ${entry.value}")
}
a.put("오마이걸","번지")
println(a)
a.remove("ITZY")
println(a)
println(a["오마이걸"])
}
● 컬렉션 함수
fun main() {
var nameList = listOf("박수영","김지수","김다현","신유나","김지우")
// 리스트 for 문
nameList.forEach{ print(it + " ") }
println()
// 시작 문자 확인
println(nameList.filter{ it.startsWith("김") })
// map 을 통해 리스트 조회
println(nameList.map{"이름 : "+it})
// 데이터 중 있으면 true / 없으면 false
println(nameList.any{ it == "김지우" })
// 전체 데이터가 맞으면 출력
println(nameList.all{ it.length == 3 })
// 아무도 없으면 true / 하나라도 있으면 false
println(nameList.none{ it.startsWith("이") })
// 조건이 맞는 첫번째 데이터 출력
println(nameList.first{ it.startsWith("김") })
// 조건이 맞는 마지막 데이터 출력
println(nameList.last{ it.startsWith("김") })
// 조건이 맞는 리스트 카운트
println(nameList.count{ it.contains("지") })
}
● 상수(companion)
늘 고정적인 값으로 사용할 때에는 상수를 통해 객체의 생성없이 메모리에 값을 고정하여 사용함으로써 성능을 향상시킬 수 있음
상수는 항상 대문자로 표기를 하여 상수라는 것을 누구나 알 수 있게끔 해야됨
fun main() {
val foodCourt = FoodCourt()
foodCourt.searchPrice(FoodCourt.FOOD_CREAM_PASTA)
foodCourt.searchPrice(FoodCourt.FOOD_STEAK)
foodCourt.searchPrice(FoodCourt.FOOD_PIZZA)
}
class FoodCourt{
fun searchPrice(foodName: String){
val price = when(foodName){
FOOD_CREAM_PASTA -> 13000
FOOD_STEAK -> 25000
FOOD_PIZZA -> 15000
else -> 0
}
println("${foodName} 의 가격은 ${price} 입니다")
}
// 늘 고정적인 값으로 사용할 때에는 상수를 통해 객체의 생성없이
// 메모리에 값을 고정하여 사용함으로써 성능을 향상시킬 수 있음
companion object{
const val FOOD_CREAM_PASTA = "크림파스타"
const val FOOD_STEAK = "스테이크"
const val FOOD_PIZZA = "피자"
}
}
● 코루틴(Coloutin)
import kotlinx.coroutines.*
fun main() {
// runBlocking 안의 모든 코루틴이 끝날 때까지
// 현재 스레드를 블로킹(멈춤)
runBlocking{
// launch: 반환값 없이 코루틴 실행 (Job 반환)
val a = launch{
for(i in 1..5){
println(i)
delay(10)
}
}
// async: 결과값을 반환하는 코루틴 실행 (Deferred<T> 반환)
val b = async{
"async 종료"
}
println("async 대기")
// await(): Deferred에서 결과를 가져옴.
// 결과가 준비될 때까지 현재 코루틴을 일시 중단
println(b.await())
// join(): Job이 끝날 때까지 현재 코루틴을 일시 중단
a.join()
println("launch 종료")
}
}
● 코루틴(Coloutin) - withTimeoutOrNull
withTimeoutOrNull(시간) 안에 함수가 종료되면 null 을 내뱉음
import kotlinx.coroutines.*
fun main() {
runBlocking{
var result = withTimeoutOrNull(50){
for(i in 1..10){
println(i)
delay(10)
}
"Finish"
}
println(result)
}
}
출처
코틀린 - https://play.kotlinlang.org/
디모의 Kotlin 강좌 - https://www.youtube.com/watch?v=8RIsukgeUVw&list=PLQdnHjXZyYadiw5aV3p6DwUdXV2bZuhlN&index=1&pp=iAQB
'개발지식' 카테고리의 다른 글
Kotlin 기본 함수(예시 코드) (7) | 2025.08.12 |
---|---|
Kotlin 기본 문법(예시 코드) (5) | 2025.08.11 |
포트포워딩(port forwarding)으로 내부망 PC 접근하기(포트포워딩 설정방법) (4) | 2025.07.28 |
(JPA) mappedBy 완벽 이해! (8) | 2025.07.26 |
(JPA) 연관관계 매핑 (3) | 2025.07.25 |