Scala

Scala의 static, companion object

partner_jun 2017. 2. 24. 19:17

스칼라는 자바와 다르게 static 키워드가 없다. 

대신 비슷한 역할을 할 수 있게 클래스와 같은 이름을 가지는 object를 만들 수 있다.

이렇게 만들어진 object를 companion object(동반 객체)라고 하고 

같은 이름을 가진 클래스를 companion class(동반 클래스) 라고 한다.


class Dog(name: String) {
def bark = println("bark! bark!")
def getName = name
}

object Dog {
def apply(name: String) = new Dog(name)
}

object안에 필드나 메소드를 구현해 자바에서 static 키워드를 사용한 것과 같이 사용할 수 있다.

또, 위와 같이 apply 메소드를 구현해 new 키워드 없이 객체를 만들거나 

unapply를 구현해 패턴 매칭에 사용할 수도 있다.


아무 생각 없이 사용하는

val lst = List(1, 2, 3)

lst match {
case h::t =>
...
}

같은 코드에서의 List는 companion object인 것이다.





재미있게도 런타임 코드에서는 static으로 되어있음을 자바 리플렉션으로 확인 할 수 있다.

class Dog(name: String) {
def bark = println("bark! bark!")
}

object Dog {
val age = 2
def barkable = true
def apply(name: String) = new Dog(name)
}

object Test extends App {
val dog = Dog("dog1")
val dogClass = dog.getClass
dogClass.getDeclaredFields.foreach(println)
dogClass.getDeclaredMethods.foreach(println)

/* 결과
public static pack.Dog pack.Dog.apply(java.lang.String)
public static boolean pack.Dog.barkable()
public static int pack.Dog.age()
public void pack.Dog.bark()
*/
}


결국 companion object - companion class는 같은 클래스를 인스턴스 부분과 static 부분으로 분리해둔 것이라고 볼 수 있다.

그렇다면 private 접근 제한자는 어떨까? 같은 클래스라면 제한없이 접근할 수 있을 것이다.

class Dog(name: String) {
private val color = "black"
def bark = println("bark! bark!")
}

object Dog {
val dog = new Dog("dog2")
dog.color // 아무런 문제가 없다.
dog.name // 접근 불가능
}

private로 선언된 필드 color에 접근이 가능했다.

하지만 생성자 파라미터의 기본 접근제한자가 private임에도 name에는 접근이 불가능했다.


둘 다 private지만 []로 추가하는 세부 지정이 있기 때문에 이런 차이를 보인다.

class Dog(private val name: String) {
private[this] val color = "black"
def bark = println("bark! bark!")
}

object Dog {
val dog = new Dog("dog2")
dog.color // 접근 불가능.
dog.name // 문제없음.
}

생성자에는 private val 키워드를 붙이고 

color의 접근제한자를 private대신 private[this]로 사용했다.

위와 반대로 color에는 접근이 불가능하고 name에는 접근이 가능해진다.