프로퍼티와 초기화 (2/2)

장똑대·2022년 4월 4일
0

Do it! 코틀린 프로그래밍 [둘째마당, 객체 지향 프로그래밍] 학습

✏️3. 정적 변수와 컴패니언 객체✏️

정적 변수(Static Variable)나 컴패니언 객체(Companion Object)를 사용하면 동적인 초기화 없이 변수를 사용할 수 있음. 이것은 동적인 메모리에 할당 해제되는 것이 아닌 프로그램을 실행할 때 고정적으로 가지는 메모리로 객체 생성없이 사용할 수 있음


3-1. 정적 변수와 컴패니언 객체

  • 일반적인 클래스의 객체 생성 없이 정적 변수나 메서드를 사용하면 프로그램 실행 시 메모리를 고정적으로 가지게 되어 따로 인스턴스화할 필요 없이 사용 할 수 있음
  • 독립적으로 값을 가지고 있기 때문에 어떠한 객체라도 동일한 참조값을 가지고 있어 해당 클래스의 상태에 상관없이 접근할 수 있음

📌 컴패니언 객체 사용하기

  • 코틀린에서는 정적 변수를 사용할 때 static 키워드가 없는 대신 컴패니언 객체를 제공
  • 컴패니언 객체는 실제 객체의 싱글톤(Singleton)으로 정의
    • 싱글톤 : 전역 변수를 사용하지 않고 객체를 하나만 생성하도록 하며, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 디자인패턴
    • 객체가 서로 동일한 정보를 가질 때 하나의 메모리만 유지해 자원의 낭비를 줄일 수 있음
class Person {
	companion object {
    	var language: String = "Korean"
    }
}

fun main() {
	println(Person.language) // 객체의 생성 없이도 접근 가능
}

📌 코틀린에서 자바의 static 멤버 사용하기
⬇️ Customer.java

public class Customer {
	public static final String LEVEL = "BASIC" // static 필드
    public static void login() {} // static 메서드
}

⬇️ CustomerAccessInKotlin.kt

fun main() {
	println(Customer.LEVEL)
    Customer.login()
}

📌 자바에서 코틀린 컴패니언 객체 사용하기

  • @JvmStatic 애노테이션(Annotation) 표기법 사용

⬇️ KCustomer.kt

class KCustomer {
	companion object {
    	// const : 컴파일 시간의 상수
    	const val LEVEL = "Intermediate"
        @JvmStatic fun login() = println("Login..") // 애노테이션 사용
        
        // 애노테이션은 함수 이름 위에 작성해도 됨
        @JvmStatic
        fun login() { }
    }
}

⬇️ KCustomerAccessInJava

public class KCustomerAccessInJava {
	public static void main(String[] args) {
    	System.println(KCustomer.LEVEL);
        KCustomer.login();
        
        // 코틀린에서 애노테이션을 사용하지 않았을 경우
        // 이와같이 코틀린의 클래스에 접근 할 수 있음
        KCustomer.Companion.login();
    }
}
  • const
    • 컴파일 시간의 상수 -> val과 다르게 컴파일 시간에 이미 값이 할당되는 것으로 자바에서 접근하기 위해서 필요
    • val은 실행 시간에 할당
    • Int형, Double형과 같이 기본형으로 사용할 자료형과 String형에만 적용 가능

3-2. 최상위 함수(Top-level Function)

최상위 함수는 클래스 없이 만들어진 함수로, 객체 생성 없이도 main()함수 어디서든 실행할 수 있음.
패키지 레벨 함수(Package-level Function)라고도 함


📌 최상위 함수 사용하기

  • 최상위 함수는 JVM에서 실행되기 위해 static으로 선언되어 있음

⬇️ PackageLevelFunction.kt

fun packageLevelFunction() { }
  
fun main() {
	packageLevelFunction()
}

📌 자바에서 최상위 함수 접근하기

public class PackageLevelAccess {
	public static void main(String[] args) {
    	PackageLevelFunctionKt.packageLevelFunc();
    }
}

-> PackageLevelFunction.kt을 디컴파일여 생성된 클래스명(PackageLevelFunctionKt)을 통해 접근

📌 지정한 클래스명으로 접근하기

⬇️ Kotlin

@file:JvmName("PKLevel") // 접근할 클래스 이름을 직접 지정

package ...

fun packageLevelFunction() { }
  
fun main() {
 packageLevelFunction()
}

⬇️ Java

public class PackageLevelAccess {
	public static void main(String[] args) {
    	PKLevel.packageLevelFunc(); // 지정한 클래스명을 통해 접근
    }
}

3-3. object와 싱글톤

새로 하위 클래스를 선언하지 않고 조금 변경한 객체를 생성하고자 할 때 사용

📌 object 선언

  • 접근 시점에 객체 생성
  • 생성자 호출을 하지 않으므로 주 생성자와 부 생성자를 사용할 수 없음
  • 클래스나 인터페이스를 상속할 수 있음
// object 키워드를 사용한 방식
object OCustomer {
	var name = "Kildong"
    val HOBBY = Hobby("Basketball)
    fun greeting() { }
    
    // 최초 접근시 실행
    init {
    	println("init block")
    }
}

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

class Hobby(val name: String)

fun main() {
    Ocustomer.greeting() // 객체의 접근 시점 (init블록 실행)
	OCustomer.name = "Ddockdae" 
    
    Ccustomer.greeting()
	CCustomer.name = "Ddockdae2" 
}

-> object로 선언된 OCustomer는 멤버 프로퍼티와 메서드를 객체 생성 없이 이름의 점(.)표기법으로 바로 사용 가능
-> 단일 인스턴스를 생성해 처리하기 때문에 싱글톤 패턴에 이용'
-> 디컴파일된 코드에서 OCustomer 객체는 INSTANCE라는 이름으로 static 블록에서 생성됨(java에서 접근할 때 사용)

📌 자바에서 object 선언의 접근

public class OCustomerAccess {
	public static void main(String[] args) {
    	// INSTANCE를 통해 코틀린의 object 선언 객체의 메서드 접근
		String name = OCustomer.INSTANCE.getName();
	}
}

📌 object 표현식

  • object 선언과 달리 이름이 없으며 싱글톤이 아님
  • object 표현식이 사용될 때마다 새로운 인스턴스가 생성됨
  • 하위 클래스(자식 클래스)를 만들지 않고도 특정 메서드를 오버라이딩 할 수 있음
open class Superman() {
    fun talk () { }
    open fun fly() { }
}

fun main() {
	// object 표현식으로 fly()구현 재정의
	val pretendedMan = object: Superman() {
    	override fun fly() { /* 함수 재정의 */ }
    }
	
    pretendedMan.talk()
    pretendedMan.fly()
}

📌 안드로이드에서의 활용

window.addMouseListener(object: MouseAdapter() {
	override fun mouseClicked(e: MouseEvent) {...}
    
    override fun moseEntered(e: MouseEvent) {...}
})

-> 2개의 메서드가 MouseAdapter()를 통해서 오버라이딩하고 클래스의 이름 없이 사용

profile
장똑대와 안드로이드

0개의 댓글

관련 채용 정보