본문 바로가기
언어/Kotlin

[Kotlin 문법 종합] - Single-expression function, 싱글턴 (@@질문하기)

by 젼젼39 2024. 3. 6.

 

 

 

1. Single-expression function

    : 람다식을 이용해 메소드를 간결하게 정리 가능

    * 람다식 구조 : 다른 함수의 인자로 넘김 / 함수의 결과값으로 반환 / 변수에 저장 하는 함수

{매개변수1, 매개변수2... -> 
    코드
}

    * 예시 1 : 세 개의 숫자를 받아 평균을 반환하는 함수(를 람다식으로 정의)

fun add(num1:Int, num2:Int, num3:Int) = (num1+num2+num3)/3
fun main(){
    println(lambdaExample({x,y -> x+y}, 20, 30)) 	//람다식 함수를 인자로 넘김
}

fun lambdaExample(sum: (Int, Int) -> Int, a: Int, b: Int): Int = sum(a, b)

//위와 동일
fun lambdaExample(sum: (Int, Int) -> Int, a: Int, b: Int) : Int) : Int {
                   //자료형이 람다식으로 선언됨
    return sum(a,b) 		//sum은 람다식의 표현문에 따라 a+b의 정수 결과를 리턴함
}

    * 예시 2 : 동일한 로직을 메소드 선언 없이 저장하기

var add = {num1: Int, num2: Int, num3: Int -> (num1+num2+num3) / 3}
						// -> 를 통해 = 없이 우측 코드를 가짐을 나타냄. 변수처럼!
println("평균값은 ${add(10,20,30)}입니다")

 

// 변수에 할당하는 람다식 변수 @@추가하

fun main(){
    var result : Int
    val example = {x: Int, y: Int -> x * y} 		//일반 변수에 람다식 할당
    result = example(10,30) 		//람다식이 할당된 변수는 함수처럼 사용 가능
    println(result)
}

//300

val example: (Int, Int) -> Int 		//람다식의 자료형 선언
    = {x: Int, y: Int -> x*y}

 

2. 싱글턴

    : 메모리 전역에서 유일한 객체임을 보장 (모든 객체에 의해 공유되는 효과...)

    - 싱글턴으로 만든 인스턴스는 메모리 전역에서 유일 & 위치정보가 고정됨. 동일
    - 프로그램이 실행되는 시점에 바로 메모리에 로드됨

    (+) 전역적으로 활용 가능, 다른 클래스들에서 쉽게 접근 가능
    (+) 효율적인 메모리 활용 가능
    (+) 객체 차원에서의 충돌 방지

    //ex. 1개의 프린터기, 공동사용 

companion, object로 구현

    - 생성자 안 적어도 됨. 자바랑 다르네

?@JvmStatic 뭐지...281~

class KCustomer{
    companion object{
        const val LEVEL = "INTERMEDIATE"
        @JvmStatic fun login() = println("Login")
    }
}

@JvmStatic 애노테이션 : 자바 소스에서 코드를 해석할 때 Companion을 생략할 수 있게 함

KCustomer.login();

KCustomer.Companion.login(); 		//애노테이션 사용하지 않은 경우

@JvmField 애노테이션 : 프로퍼티를 자바에서 사용하고자 할 경우

 

 

//object 키워드를 사용한 방식
object OCustomer{
    var name = "철이"
    fun greeting() = println("Hello World")
    val HOBBY = Hobby("Basketball")
    init{
        println("Init!")
    }
}

//컴패니언 객체를 사용한 방식
class CCustomer{
    companion object{
        const val HELLO = "hello" 	//상수 표현
        var name = "미애"
        @JvmField val HOBBY = Hobby("Football")
        @JvmStatic fun greeting() = println("Hello World")
    }
}

class Hobby(val name: String)

fun main() {
    OCustomer.greeting()    //객체의 접근 시점
    OCustomer.name = "기영"
    println("name = ${OCustomer.name}")
    println(OCustomer.HOBBY.name)

    CCustomer.greeting()
    println("name = ${CCustomer.name}, HELLO = ${CCustomer.HELLO}")
    println(CCustomer.HOBBY.name)
}

    - object로 선언된 OCustomer는 멤버 프로퍼티, 메서드를 객체 생성하지 않고도 . 으로 접근할 수 있음

    - 단일 인스턴스를 생성해 처리하기 때문에 싱글톤 패턴에 사용됨

    - object 선언 방식 사용 시 접근 시점에 객체 생성됨 -> 생성자 호출을 하지 않음 = object 선언 시 주/부 생성자 사용 불가

    - 수정 가능

 

2024.03.15 - [언어/Kotlin] - [Kotlin 공부] object와 싱글톤, object와 compaion

 

[Kotlin 공부] object와 싱글톤, object와 compaion

dd

sugapowderjj.tistory.com

 

 

객체 생성하지 않고도 클래스 정보에 접근 가능

1)  생성자 호출하지 않는 경우

fun main() {
    Bird.fly("참새") 		//객체 생성 없이 클래스 이름.메서드( )
}

object Bird {
    fun fly(name:String) {
        println("${name}가 날아요~")
    }
}
class Person{
    var id: Int=0
    var name: String = "철이"
    companion object{
        var language : String = "Korean"
        fun work(){
            println("working")
        }
    }
}

fun main(){
    println(Person.language) 	//인스턴스 생성하지 않고도 사용 가능
    Person.language = "Engligh" 	//기본값 변경 가능
    println(Person.language) 	//변경된 내용을 출력함
    Person.work() 	//메서드 실행
    
    //println(Person.name) 	//name은 컴패니언 객체가 아니니까 안됨
    
}

 

2) 생성자를 호출하는 경우

fun main() {
    // trash와 같이 생성자에 매개변수 전달 가능
    var singletonObject1 = MySingletonClass.getInstance(trash = 1)
    singletonObject1.setNum(5)
    println("num값은: ${singletonObject1.getNum()}")

    // singletonObject2에서 num을 10으로 대입
    var singletonObject2 = MySingletonClass.getInstance(trash = 1)
    singletonObject2.setNum(10)

    // singletonObject1의 num이 10으로 출력됨
    // singletonObject1과 singletonObject2는 같은 객체를 공유하기 때문
    println("num값은: ${singletonObject1.getNum()}")

}

class MySingletonClass private constructor() {
    private var num:Int = 0

    companion object {
        @Volatile private var instance: MySingletonClass? = null
        private var trash = 0

        fun getInstance(trash: Int): MySingletonClass {
            this.trash = trash
            // 외부에서 요청왔을때 instance가 null인지 검증
            if(instance == null) {
		            // synchronized로 외부 쓰레드의 접근을 막음
								// 쓰레드는 다음챕터에서 소개합니다!
		            // 쓰레드간의 객체상태 혼돈을 막기위해 사용한다고 이해해주세요
                synchronized(this) {
                    instance = MySingletonClass()
                }
            }
            return instance!!
            
//            엘비스연산자와 뒷장에서배울 scope function을 이용하면
//            아래와같이 더욱 직관적인 코드 작성이 가능합니다
//            return instance ?: synchronized(this) {
//                // also는 호출한 객체를 it으로 넘김
//                // instance가 null이라면 새로 생성하고 아니면 무시함
//                instance ?: MySigletonClass().also {
//                    instance = it
//                }
//            }
        }
    }
    fun setNum(num: Int) {
        this.num = num
    }

    fun getNum(): Int{
        return this.num
    }
}