클래스와 오브젝트#1

2018, Jun 15    

visibility modifier(가시성 변경자)


코틀린에서 클래스 선언시 별다른 modifier를 붙이지 않는다면 기본적으로 public으로 정의된다.

코틀린에서는 자바에서와 같은 패키지 전용 접근 제어자는 없고, 그에 대한 대안으로 internal을 도입하였다.
internal은 “같은 모듈 내부에서만 접근 가능“하며, 여기서 모듈은 한 번에 한꺼번에 컴파일 되는 코틀린 파일들을 의미한다.
private 는 같은 파일에서만 접근 가능하다는 것을 의미한다.

modifier 클래스 멤버 최상위 선언
public(기본) 모든 곳에서 볼수 있다. 모든 곳에서 볼수 있다.
internal 같은 모듈 안에서만 볼 수 있다. 같은 모듈 안에서만 볼 수 있다.
protected 하위 클래스 안에서만 볼 수 있다. (최상위 선언에 적요할 수 없음)
private 같은 클래스 안에서만 볼 수 있다. 같은 파일 안에서만 볼 수 있다.

아래 TalkativeButton 메소드는 모두 syntax가 발생하는데, 하나씩 확인해 보자.


internal open class TalkativeButton : MyInterface {

    private fun yell() = println("Hey")
    protected fun whisper() = println("Let's talk!")
}

fun TalkativeButton.giveSpeech() { //Error--- (1)
    yell()  //Error--- (2)
    whisper()  //Error--- (3)
}
  • (1) public인 멤버가 자신의 “internal”타입인 “TalkativeButton”을 노출함.
  • (2) yell함수는 private이므로 TalkativeButton의 내에서만 접근 가능하다.
  • (3) TalkativeButton의 하위 클래스가 아니므로 접근 불가

  • 컴파일된 코틀린의 public, protected, private 변경자는 컴파일된 자바 바이트코드 안에서도 그대로 유지 된다.
    internal 변경자의 경우는, 자바에 딱 맞는 가시성이 없어 바이트 코드상에서는 public이 된다.
    이런 차이 때문에 코틀린에서는 접근할 수 없는 대상을 자바에서 접근할 수 있는 경우가 생긴다.

  • 코틀린 컴파일러는 internal 멤버의 이름을 변경하는데, 이는 한 모듈에 속한 어떤 클래스를 모듈 밖에서 상속한
    경우 그 하위 클래스 내부의 메소드 이름이 우연히 상위 클래스의 internal 메소드와 같아져서 내부 메소드를 오버라이드하는
    경우를 방지하고, 실수로 internal 클래스를 보듈 외부에서 사용하는 일을 막기 위함이다.

내부 클래스


자바와는 달리 코틀린에서는 내부에 선언된 클래스에서 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다.
이는 자바의 static중첩 클래스와 동일하다.


먼저 java에서의 InnerClass(내부 클래스)와 NestedClass(중첩 클래스)를 살펴 보자.
[내부 클래스 in JAVA] 내부클래스에서 외부 클래스에 대한 참조를 묵시적으로 포함한다.

public class InnterTest {

    int resource = 0;
    static int static_resource = 1;

    class _Inner {

        //내부 클래스에서는 static 선언 불가
        int _resource = 2;

        /* 내부 클래스는 바깥쪽 클래스에 대한 참조를 묵시적으로 포함한다. */
        public void _use() {
            System.out.println(resource);
            System.out.println(static_resource);
        }
    }

    public void use() {
        _Inner i = new _Inner();
        i._use();
        System.out.println(i._resource);
    }
}


[중첩 클래스 in JAVA] 내부클래스가 static이라서 바깥 클래스의 static멤버가 접근 가능하다.

public class NestedTest {

    int resource = 0;
    static int statc_resource = 1;

    /*
        중첩클래스 :
            내부 클래스이지만 static이라서 바깥 클래스의 static멤버에만 접근이 가능하다.
    */
    static class _Nested {
        int _resource = 2;
        static int _static_resource = 3;

        public static void _use() {

            //static 멤버가 아니므로 접근 불가
            //System.out.println(resource);
            System.out.println(statc_resource);
        }
    }

    public void use() {
        _Nested._use();
//      System.out.println(_resource); 접근 불가
        System.out.println(_Nested._static_resource);
    }
}

코틀린에서 내부 클래스에 inner를 붙이지 않으면 자바 static중첩 클래스로 정의 된다.
[중첩 클래스 인식 : kotlin]

>>> class Outer {

     val member1 = 1;

     class Inner {

         fun use() {
             println(member1)
         }
     }
 }
error: unresolved reference: member1
            println(member1)
[inner 클래스 인식 : kotlin]
class Outer {

    val member1 = 1;

    inner class Inner {

        fun use() {
            println(member1)
        }
    }
}

>>> val i = Outer().Inner();
>>> i.use()
1

자바와 코틀린의 충첩 클래스와 내부 클래스의 관계를 정리하면 다음과 같다.

클래스 B안에 정의된 클래스 A 자바에서는 코틀린에서는
중첩 클래스 static class A class A
내부 클래스 class A inner class A