반응형

내부 클래스의 제어자와 접근성

  • 내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일

 

원래 클래스 앞에는 (default) 혹은 public 만 가능하다. 

그런데, 내부 클래스 앞에는 접근제어자 private, protected,   public, (default) 이렇게 4개가 전부 가능하다.
왜냐하면 iv, cv등의 멤버들에는 4개가 모두 가능한데, 
내부 클래스의 sope가 iv, cv, lv 변수들과 같기 때문이다. 

 

예제를 보면, InstanceInner라는 인스턴스 내부클래스가 있고, 
StaticInner라는 static내부클래스가 있고,
LocalInner라는 지역내부클래스가 있다.

여기서 핵심은, static 멤버를 가질 수 있는 것은, static내부 클래스 뿐이라는 것이다.
인스턴스 내부 클래스와 지역 내부 클래스는 static변수를 가질 수 없다.

우리가 만약에 내부 클래스를 정의했는데, 거기에 static멤버가 필요하다면,
내부 클래스가 static 내부클래스여야 한다.

왜냐하면, static 멤버는, 객체 생성없이 쓸 수 있어야 하기 때문이다.

그런데 만약에 static 내부클래스가 아닌 다른 내부클래스에 static 멤버를 정의하면, 모순이 발생하는 것이다.
예를들어, 위의 코드에서 StaticInner클래스가 static이 아니라고 가정해보자.
StaticInner클래스는 인스턴스 내부 클래스이고, 
인스턴스 내부 클래스의 scope는 iv와 같기 때문에, 객체를 생성한 후 해당 멤버들을 사용할 수 있다.
static멤버는 객체생성없이 사용이 가능해야 하는데, 현재 static멤버를 담고있는 StaticInner클래스는 인스턴스 내부 클래스이므로,   
해당 인스턴스 내부 클래스는 객체 생성전에 사용할 수 없다.

즉, static멤버가 있어도 객체 생성전엔 사용할 수 없는 모순이 발생하는 것이다.

따라서, 내부 클래스에 static멤버를 가져야 하면, 해당 내부 클래스는 반드시 static 내부 클래스로 선언해야 한다.

 

그리고, 6장에서 공부한 것 처럼, 
인스턴스 메스드와 static 메서드를 공부했던 것 처럼,

인스턴스 내부 클래스의 인스턴스 멤버는 static내부 클래스의 static멤버를 사용할 수 있지만,
static 내부 클래스에서는 외부 클래스의 인스턴스 멤버를 사용할 수 없다.
(iv가 cv를 사용할 수 는 있지만, cv가 iv를 사용하지 못하는 것과 같은 경우임)

이외로, 추가로 짚고 넘어가야 하는 것은, 
final이 붙은 static은 static내부 클래스가 아니어도, 허용된다.
즉, 상수인데 static의 성격을 띄고 있는 경우에는 가능하다. (객체에 상관없이 사용되는 상수)

 

 

그리고, 이 상수를 사용하려면 어떻게 해야하냐면,
내부클래스이름.상수이름 으로 접근할 수 있다.

그리고, static멤버도, 내부클래스이름.멤버명 으로 접근할 수 있다.

그런데, 지역 내부 클래스의 상수에는 위의 방식으로 접근할 수 없다. 위와같은 방식으로 접근하려 하면 에러가 발생한다.
왜냐하면, 지역 내부 클래스는 해당 메서드 안에서만 사용할 수 있기 때문이다.

예제를 통해 확인해 보면, 
지역 내부 클래스 안의 상수는, 해당 지역 내부 클래스를 담고 있는 메서드 안에서만 사용이 가능한 것을 확인할 수 있다.

 

이번 예제는, static멤버와 인스턴스 멤버들끼리 사용하는 것에 대한 내용이다.
앞서 공부했듯, 인스턴스 멤버가 static 멤버를 사용하는 것은 항상 된다.
그러나, static멤버가 인스턴스 멤버를 사용하는 것은 안된다.

이것이 내부 클래스에도 똑같이 적용된다. 

InstanceInner라는 인스터스 내부 클래스가 있고,
StaticInner라는 static 내부 클래스가 있다.

멤버 변수를 보면, iv는 인스턴스 멤버이므로 인스턴스 내부클래스에 접근하는 것이 가능하다.
그리고, static멤버가 static멤버를 참조하는 것도 가능하다.

그런데, 만약에, static멤버가 인스턴스 멤버를 바로 쓰려고하면 에러가 난다.

이번에는 메서드를 보자.
static메서드에서 static내부클래스에 접근하는 것은 OK이다.

static메서드에서 인스턴스내부클래스에 접근하려고 하면 불가능하다.
그러나, outer 클래스의 객체를 생성한 다음에는 가능하지만,  보통, 이렇게 쓸 필요까진 없다.

중요한 것은, static 멤버는 인스턴스멤버에 직접접근이 불가능하다는 것 이다.

원래는 같은 클래스에 이있으면 가능해야 하지만, static멤버가 인스턴스 멤버에 접근 할 수 없기 때문에 불가능하다.

 

이번에는 인스턴스 메서드에서는,  둘다 가능하다.
인스턴스 멤버는 static멤버를  사용할 수 있다.

 

그리고,  지역 내부 클래스에서는 해당 메서드 안에서만 사용가능하다.

 

 

세번째 예제의 핵심은, 
코드에서 outerIv라는 private멤버가 있는데,

내부 클래스에서 Private멤버에 접근할 수 있다. 

원래 Private멤버는 해당 클래스에서만 사용가능하고, 다른 클래스에서는 사용할 수 없는데, 
이 내부 클래스는 Private멤버가 있는 클래스 안에 있으므로, 사용이 가능하다.

즉, 내부 클래스에서는 외부 클래스의 private 멤버도 접근가능하다.

그런데, static내부 클래스에서는 인스턴스 멤버에 접근할 수 없기 때문에,
외부 클래스의 private 멤버를 당연히 사용할 수 없다.

static 내부클래스의 static멤버는 외부 클래스의 static멤버는 사용할 수 있다. 

 

그리고, 지역 내부 클래스에서 중요한 것은, 
메서드에 lv변수와 LV상수가 있는데, 

지역 내부 클래스에서는 변수는 접근할 수 없고, final이 붙은 상수 LV 접근할 수 있다.

왜냐하면, 메서드의 변수는 지역변수라서, 메서드 종료와 함께 소멸되는데,
메서드의 지역변수보다 지역 내부 클래스의 객체가 더 오래 존재하는 것이 가능하기 때문이다.

즉 LV보다 지역 내부 클래스의 객체가 더 오래 존재 할 수 있다.
그런데, 지역 내부 클래스에서 상수가 아니라 lv사용이 가능하면,
메서드는 종료된 상태인데, 지역 내부 클래스의 객체만 존재하고 있는 상태라면, 
사용하려는 lv가 없어져 있을 것이다. 
이러한 문제점이 있을 수 있기 때문에 지역 내부 클래스에서는 lv는 사용할 수 없다. 

(JDK1.8부터는 final생략 가능)
변수인데, 값이 안바뀌는 것을 자동적으로 상수로 취급한다.

 

 

이번 예제는, 외부 클래스의 바깥에서 내부클래스를 어떻게 사용할 수 있는지에 대한 예제이다.

Outer2클래스의 내부클래스가 3개있다.
InstanceInner라는 내부 클래스를 사용하려면, 외부 클래스의 객체를 먼저 생성해야 한다.
그래서 Outer2객체를 먼저 생성했다.

그리고나서, 내부 클래스의 인스턴스를 생성할 수 있다.
인스 턴스내부 클래스도 Outer2클래스의 인스턴스 멤비이므로, 인스턴스 멤버는 객체를 만들어야 쓸 수 있는 것과 같은 이치다.

StaticInner는 Static내부 클래스이므로,
객체를 생성하지 않고 바로 사용할 수 있다.
그래서, 객체를 생성하지 않고도 Outer2.StatincInner의 cv에 바로 접근할 수있다.

그리고, 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
그냥 내부 클래스를 생성하면 되는데, new Outer2.StaticInner(); 처럼 앞에 내부 클래스의 이름을 붙여준다.

 

그리고 한가지 더 알아보자면,
위의 예제 7-15를 컴파일하면, 클래스가 5개 만들어진다.
Ex7_15클래스, Outer2클래스, 그리고 내부클래스 3개가 만들어진다. 
파일 명을 보면, 내부클래스파일의 파일명은, 외부클래스이름$가 내부클래스명 앞에 붙어서 파일명이 된다.

그런데, 지역 내부클래스는 숫자가 더 붙는다. 
왜 그러냐면, 메서드가 여러개 있을 수도 있기 때문인데, 같은 이름의 클래스가 메서드마다 있을 수 있는 경우를 고려한 것이다.

 

 

예제 7-16이다.

같은 이름의 변수가 3개가 있다.(value)
그런데, 각 value가 변수의 종류가 다른데,

외부 클래스의 iv

내부 클래스의 iv

lv

이렇게 3개가 있다.

이름이 다 같을 때, 어떻게 구별하냐는 것인데,
우리가 이미 아는 것처럼 지역변수와 iv를 구할 때, this를 쓰는 것처럼 사용하면 된다.

그런데, 외부클래스의 iv는 어떻게 구별하냐면, 외부클래스의이름.this를 하면 된다.

즉 변수명이 value일때,

외부 클래스의 iv는, Outer3.this.value

내부 클래스의 iv는 this.value

lv는 그냥 value이다. (가장 가까운 것이므로 lv다)

반응형

'JAVA' 카테고리의 다른 글

프로그램 오류, 예외 클래스의 계층구조  (0) 2022.04.08
익명 클래스  (0) 2022.04.08
내부 클래스의 종류, 특징, 선언  (0) 2022.04.07
디폴트 메서드와 static메서드  (0) 2022.04.07
인터페이스의 장점 (2)  (0) 2022.04.07