Home 자바 static의 문제점, 코틀린의 `companion object`의 의미
Post
Cancel

자바 static의 문제점, 코틀린의 `companion object`의 의미

객체지향 프로그래밍이라는 수업에서는 객체지향의 개념과 그것을 익히기 위한 도구로서 자바 언어에 대해 배운다.

오늘은 자바 문법 중 ‘static’ 멤버에 대한 진도를 나갔다. 교수님께서 static의 문법적인 부분을 나가시면서 절대 실제로 사용해서는 안 되고, 자바에서 사라져야 문법이라고 강력하게 주장하셨던 게 기억에 남아서 이렇게 글을 쓴다.

1
2
3
4
5
6
7
8
9
10
11
class A {
    public static int n;
    public static void f() { ... }
}

public static void main(String[] args) {
    A a1 = new A();
    A.n = 10;
    a1.n = 20; // <---
    System.out.println(A.n); // 20
}

결론부터 말하자면 static 멤버는 항상 {클래스 이름}.으로 시작해서 접근해야만 한다. 하지만 위 코드의 9번째 줄에서는 {객체 이름}.으로 static 멤버에 접근하고 있다. 이렇게 작성하더라도 컴파일/런타임 에러가 나지 않는다. 자바 문법에 있으니까.

심지어 교과서에도 static 멤버에 대해 “모든 객체들이 공유하는 멤버”라는 식으로 설명하고 있다고 한다. 그렇다면 왜 교수님은 이러한 이미지를 가지는 것에 대해 반대하시는 걸까?

첫 번째 이유는 이 방식이 비효율적이고 생산성이 떨어진다는 것에 있다. 또한 저렇게 접근하는 게 큰 의미가 있지도 않다. 만약 static 멤버는 항상 {클래스 이름}.으로 접근해야 하고, {객체 이름}.으로는 non-static 멤버만 접근할 수 있다고 가정해보자. 그렇다면 만약 다른 사람이 쓴 코드를 읽다가 {클래스 이름}.으로 클래스 내 멤버에 접근했다면 클래스 명세를 찾아가보지 않아도 해당 멤버는 static이라는 사실을 단번에 알 수 있다. 마찬가지로 {객체 이름}.으로 접근했을 때도 멤버가 non-static일 것이므로 해당 객체 내에만 영향이 있을 것이라고 추측할 수 있다.

반대로 위에서 한 가정이 없다고 해보자. 이는 현재 자바의 상황과 동일한데, {객체 이름}.으로 접근할 수 있는 것이 static 멤버일 수도 있고, non-static 멤버일 수도 있다. 그래서 다른 사람이 작성한 코드 중 {객체 이름}.으로 접근한 것이 있다면 그것이 static인지 non-static인지 확인하러 클래스 명세에 들러야 하는 번거로움이 발생한다. 굳이 그것을 확인해야 하는 이유는 만약 그 멤버가 static이라면 다른 객체에 영향을 줄 수 있기 때문에.

두 번째로는 객체지향 철학에 어긋나기 때문이다. 객체지향이란 우리가 이 세상을 객체들의 집합으로 보는 관점을 똑같이 프로그래밍 세계에 접목시켜 문제를 해결하고자 하는 패러다임이다. 그런데 실세계의 객체 중에 개인의 특성이 바뀌었다고 다른 객체까지 동시에 영향을 받는 경우는 없다.

코틀린이나 최근에 출시된 언어들은 이러한 의미론적 취약점들을 보완했다. 대표적인 예가 코틀린의 companion object이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
    companion object {
        var n = 10;
        fun foo() { ... }
    }
}

void main() {
    A.foo()
    A.n = 20

    val a = A()
    a.foo() // 불가
    a.n = 30 // 불가
}

클래스 내의 companion object 블록 안에 멤버들을 정의하면 자바에서 static 키워드를 붙인 것과 거의 같은 동작을 보여준다. 또한 앞서 언급한 문제도 애초에 발생될 수 없게 설계되어 있다. companion object의 문법적인 내용은 공식문서에 자세히 나와있다.

사실 나는 지금까지 companion object는 그저 자바의 static을 대체한 것이고, 차이점이라고 해봐야 블록으로 묶어서 좀더 보기 편하다는 것?정도로만 알고 있었다. 확실히 코틀린이 고민을 많이 해서 만든 언어라는 생각과 동시에 코틀린에 대해 나름 잘 알고 있다고 생각했던 착각이 깨지던 순간이었다. 알고 있다고 생각해도 자만하지 말고 꼼꼼히 공부해야겠다.

This post is licensed under CC BY 4.0 by the author.

[Git] Pull Request 반으로 쪼개기🔪

-