Skip to content

Latest commit

Β 

History

History
229 lines (169 loc) Β· 6.64 KB

2021-04-15-kotlin-companion.md

File metadata and controls

229 lines (169 loc) Β· 6.64 KB

듀어가기전에 ..

kotlin을 μ‚¬μš©ν•˜λ©΄μ„œ λΆˆνŽΈν–ˆλ˜(ν˜Ήμ€ μ΅μˆ™μΉ˜ μ•Šμ•˜λ˜) 뢀뢄이 3가지 정도 μžˆμ—ˆλŠ”λ°μš”.

  1. Nullable,
  2. singleton(default final)
  3. static

μœ„ λ‚΄μš© 쀑, static 에 κ΄€ν•˜μ—¬, μ™œ kotlin이 static 을 μ§€μ›ν•˜μ§€ μ•ŠλŠ”μ§€ ν˜Ήμ€ μœ μ‚¬ν•˜κ²Œ λ§Œλ“€λ €λ©΄ μ–΄λ–»κ²Œν•΄μ•Όν•˜λŠ”μ§€λ₯Ό μ •λ¦¬ν•΄λ³΄λ €ν•©λ‹ˆλ‹€.

kotlin object keyword

  • kotlin μ—μ„œλŠ” singleton 을 μ–Έμ–΄μ—μ„œ μ§€μ›ν•©λ‹ˆλ‹€.
    • sigleton 을 보μž₯ν•˜λŠ” object keyword
object HelloWorld {
    fun helloWorld() = "helloWorld"
}

μœ„μ²˜λŸΌ μ„ μ–Έν•˜κ³ μž ν•˜λŠ” class 에 object keyword λ₯Ό λŒ€μ‹  μ‚¬μš©ν•  경우, java μ—μ„œλŠ” μ•„λž˜μ²˜λŸΌ ν‘œν˜„λ©λ‹ˆλ‹€.

public final class HelloWorld {
   @NotNull
   public static final HelloWorld INSTANCE;

   @NotNull
   public final String helloWorld() {
      return "helloWorld";
   }

   private HelloWorld() {
   }

   static {
      HelloWorld var0 = new HelloWorld();
      INSTANCE = var0;
   }
}

static final둜 객체λ₯Ό μ„ μ–Έν•˜κ³ , static block 을 μ‚¬μš©ν•΄ μ΄ˆκΈ°ν™”λ₯Ό ν•©λ‹ˆλ‹€.

ν”νžˆ λ³Ό 수 μžˆλŠ” singleton pattern의 ν˜•νƒœμž…λ‹ˆλ‹€.

public static final 둜 객체λ₯Ό μ„ μ–Έλ˜μ–΄, kotlin μ—μ„œ μ•„λž˜μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    @Test
    fun helloWorldTest() {
        val expect = "helloWorld"

        assertEquals(expect, HelloWorld.helloWorld())
    }

static method 와 μœ μ‚¬ν•˜κ²Œ μ‚¬μš© ν•  수 있으며, Java 둜 λ³€ν™˜ ν•  경우 μ•„λž˜μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

HelloWorld.INSTANCE.helloWorld()

주의 : singleton 으둜 인해 static 처럼 μ“Έ 수 μžˆλŠ”κ²ƒμ΄μ§€, static 이 μ•„λ‹™λ‹ˆλ‹€.

λ˜ν•œ objectλŠ” singleton μ—­ν•  외에도, 읡λͺ… 클래슀λ₯Ό λ§Œλ“œλŠ” keyword μ΄κΈ°λ„ν•©λ‹ˆλ‹€.

val typeReference = object : TypeReference<List<String>>() {}

kotlin companion object

μ•žμ„œ μ„€λͺ…ν–ˆλ“―, kotlin μ—λŠ” static ν•¨μˆ˜/λ³€μˆ˜λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. static κ³Ό μœ μ‚¬ν•˜κ²Œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œ, companion object λΌλŠ” keywordλ₯Ό μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ§Œ, μœ μ‚¬ν•˜κ²Œ λ™μž‘ν• λΏ μ‹€μ œλ‘œ static 으둜 μƒμ„±λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

class Hello {
    companion object {
        fun hello() = "hello"
    }
}

class World {
    fun world() = Hello.hello()
}

java 둜 λ³€ν™˜

public final class Hello {
   @NotNull
   public static final Hello.Companion Companion = new Hello.Companion((DefaultConstructorMarker)null);

  public static final class Companion {
      // code 
  }
}

nested class 둜 Companionμ΄λΌλŠ” μ΄λ¦„μ˜ class λ₯Ό μ„ μ–Έν•˜κ³ , 이λ₯Ό 객체둜 μ΄ˆκΈ°ν™”ν•˜μ—¬ λ‚΄λΆ€ λ³€μˆ˜λ‘œ λ“€κ³ μžˆλŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

μ™œ λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ μ§€μ›ν•˜λŠ”κ°€ ?

The main advantage of this is that everything is an object. link

kotlin μ—μ„œ static 을 μ§€μ›ν•˜μ§€ μ•ŠλŠ” κ°€μž₯ 큰 μ΄μœ λŠ”, static member κ°€ object(객체) 둜 μ·¨κΈ‰λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. object 둜 μ·¨κΈ‰λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” 건, 상속을 μ΄μš©ν•  수 μ—†κ³ , parameter 둜 전달될 수 μ—†μœΌλ©°, instance Map 등을 ν™œμš©ν•  수 μ—†λ‹€λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.

first citizen 이 μ•„λ‹ˆλΌλŠ” 의미죠

interface KeyGenerator {
    fun generate() : String
}


class Hello{
    companion object : KeyGenerator {
        override fun generate(): String = "this object key"
    }
}

객체의 역할이 μ•„λ‹Œ, μœ ν‹Έμ„±(?) Interface λ₯Ό μ•„λž˜μ²˜λŸΌ λΆ„λ¦¬ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ κ½€ μœ μš©ν• κ±° κ°™μ€λ°μš”. μœ ν‹Έμ„±μœΌλ‘œλŠ” μ•„λž˜μ²˜λŸΌ μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

// logger μ„ μ–Έ 
interface Log {
  fun logger() = LoggerFactory.getLogger(this.javaClass)
}

class MyBusiness{
  // companion 으둜 log 상속
  companion object : Log 
  
  fun hello(str:String) {
    logger.info("hello $str")
  }
}

μœ„μ²˜λŸΌ 자주 μ‚¬μš©λ˜λŠ” 곡톡 μœ ν‹Έλ“€μ„, object 상속을 μ΄μš©ν•΄ νŽΈν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€ :)

[μΆ”κ°€] Companion 의 νŠΉμ§•

  • Companion keyword λ₯Ό μ‚¬μš©ν•˜μ§€μ•Šκ³ , μΆ•μ•½ν•˜μ—¬ μ‚¬μš©κ°€λŠ₯ν•©λ‹ˆλ‹€. (1)
class Parent {
    companion object {
        val target = "json"
        val version = 1.0
    }
}
// test class 
@Test
@DisplayName("(1) Companion keyword λ₯Ό μ‚¬μš©ν•˜μ§€μ•Šκ³ , μΆ•μ•½ν•˜μ—¬ μ‚¬μš©κ°€λŠ₯ν•©λ‹ˆλ‹€.")
fun shortcut() {
  val expect = Parent.Companion.target

  assertEquals(expect, Parent.target)
  
  val expectType = Parent

  assertTrue("class ν• λ‹Ή μ‹œ, companion 을 λ°”λΌλ΄…λ‹ˆλ‹€.", expectType is Parent.Companion)
}
  • Companion 에 이름을 지을 수 있으며, Interface 에도 μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이름을 지을 경우, 좕약을 κ·ΈλŒ€λ‘œ μ‚¬μš©ν•  수 μžˆμœΌλ‚˜, Parent.Companion.target 을 Parent.${CompanionName}.target 으둜 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • Companion 은 λ”± ν•˜λ‚˜λ§Œ μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
interface Parent {
    companion object AppVersion {
        val target = "json"
        val version = 1.0
    }
    companion object { // error !! 

    }
}
  • java 둜 λ³€ν™˜ μ‹œ, static 객체둜 μ •μ˜λ¨μœΌλ‘œ μ™ΈλΆ€ class μ—μ„œλ„ μ ‘κ·Ό κ°€λŠ₯ν•©λ‹ˆλ‹€.
    • companion 을 private 으둜 μ„€μ •μ‹œ μ ‘κ·Ό λΆˆκ°€ν•©λ‹ˆλ‹€.
  • 객체 상속 μ‹œ, companion 은 μƒμ†λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • class ν•¨μˆ˜μ—μ„œ companion λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • companion μ—μ„œ class propertyλŠ” μ‚¬μš© λΆˆκ°€ν•©λ‹ˆλ‹€. (companion 은 static 객체 μž…λ‹ˆλ‹€.)
open class Parent {
    companion object {
        val target = "json"
        val version = 1.0
    }

    open fun getTarget(): String = Companion.target
}

class Child : Parent() {
    companion object {
        val target = "html"
        val version = 1.0
    }
    // Companion μΆ•μ•½ κ°€λŠ₯ν•˜μ§€λ§Œ, 이해λ₯Ό λ•κΈ°μœ„ν•΄ λ‚¨κ²¨λ‘‘λ‹ˆλ‹€.
    override fun getTarget() = Companion.target 
}

@Test
@DisplayName("(4) λ‹€ν˜•μ„±μ„ μ΄μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (companion 의 νŠΉμ§•μ€ μ•„λ‹˜) ")
fun polymorphism() {
  val child:Parent = Child()

  // companion 의 νŠΉμ§•μ€ μ•„λ‹ˆμ§€λ§Œ, μ΄λ ‡κ²Œ μ‚¬μš©ν•  수 도 μžˆμ„κ±° κ°™λ„€μš” :) 
  assertEquals(Child.Companion.target, child.getTarget())
}

개인적인 생각 :: java 개발자 관점(?)μ—μ„œ λ΄€μ„λ•Œ companion 은 κ·Έλƒ₯ static object 둜 λ³΄μ΄λŠ”λ°, 쑰금 더 μš°μ•„ν•œ μ‚¬μš©μ²˜κ°€ μ—†μ„κΉŒ? κΆκΈˆν•©λ‹ˆλ‹€ :)

μ°Έκ³ 

Why is there no static keyword in Kotlin?

Kotlin in Action

[kotlin] Companion Object (1) – μžλ°”μ˜ staticκ³Ό 같은 것인가?