충분히 쌓여가는
내부 클래스의 제어자와 접근성 본문
내부 클래스의 제어자와 접근성
원래 클래스 앞의 제어자는 public, (default)만 가능하다
내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일(public, (default), private, protected)
static 클래스만 static 멤버를 정의할 수 있다
내부 클래스를 정의할 때 static 멤버가 필요하면, 내부 클래스가 static 내부 클래스 이어야 한다(static 멤버 자체가 객체 생성 없이 사용가능)
[만약 제어자가 static이 아니라면 객체를 생성해야 사용가능하므로 static 멤버는 모순이된다]
상수(final)인 경우 static 멤버 사용 가능
class InnerClass {
class InstanceInner {
int iv = 1000;
// static int cv = 100; // 에러, static 변수를 선언할 수 없다
final static int CONST = 100; // final static은 상수이므로 허용
}
static class StaticInner {
int iv = 200;
static int cv = 200; // static 클래스만 static 멤버를 정의할 수 있다
}
void myMethod() {
class LocalInner {
int iv = 300;
// static int cv = 300; // 에러, static 변수를 선언할 수 없다
final static int CONST = 300; // final static은 상수이므로 허용
}
int i = LocalInner.CONST; // OK
}
public static void main(String[] args) {
System.out.println(InstanceInner.CONST);
System.out.println(StaticInner.cv);
// System.out.println(LocalInner.CONST); // 에러, 지역 내부 클래스는 메서드 내에서만 사용가능
}
}
100
200
static 내부 클래스에서는 외부 클래스의 instance 멤버에 접근할 수 없다
instance 멤버는 static 멤버에 접근 가능
public class InnerStatic {
class InstanceInner {}
static class StaticInner {}
InstanceInner iv = new InstanceInner(); // 인스턴스 멤버끼리는 직접 접근 가능
static StaticInner cv = new StaticInner(); // static 멤버끼리는 직접 접근 가능
// static StaticInner cv = new InstanceInner(); // 에러, static 멤버는 인스턴스 멤버에 직접 접근 불가
static void staticMethod() { // static 멤버는 인스턴스 멤버에 직접 접근 불가
// InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
InnerStatic outer = new InnerStatic(); // 인스턴스 클래스는 외부 클래스를 먼저 생성해야 생성가능
InstanceInner obj1 = outer.new InstanceInner();
}
void instanceMethod() { // 인스턴스 메서드에서는 인스턴스 멤버와 static 멤버 모두 접근 가능
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// LocalInner lv = new LocalInner(); // 지역 내부 클래스는 외부에서 접근할 수 없다
}
void myMethod() {
class LocalInner {}
LocalInner lv = new LocalInner();
}
}
접근 제어자 링크
private는 같은 클래스 안에서 사용 가능
외부 클래스의 지역변수는 안되고, final이 붙은 변수(상수)만 접근가능하다(JDK 1.8부터 지역 변수도 가능)
JDK 1.8부터 변수인데 값이 바뀌지 않으면 상수로 간주한다(final 생략 가능)
public class Outer {
private int outerIv = 0;
static int outerCv = 0;
// private static int outerCv = 0; // private 붙여도 가능
class InstanceInner {
int iiv = outerIv; // 1. 외부 클래스의 private 멤버도 접근가능
int iiv2 = outerCv;
}
static class StaticInner {
// int siv = outerIv; // static 클래스는 외부 클래스의 인스턴스 멤버에 접근할 수 없다
static int scv = outerCv;
}
void myMethod() {
int lv = 0; // 변수, 값이 바뀌지 않는 변수는 상수로 간주
final int LV = 0; // 상수, JDK 1.8부터 final 생략 가능
class LocalInner { 2. 지역 내부 클래스를 감싸고 있는 메서드의 상수만 사용가능
int liv = outerIv;
int liv2 = outerCv;
// 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다(JDK 1.8 이후부터 가능)
int liv3 = lv; // 에러 아님(JDK 1.8부터 에러 아님)
int liv4 = LV;
}
}
}
JDK 1.8부터 변수인데 값이 바뀌지 않으면 상수로 간주한다(final 생략 가능)
변수가 바뀔 경우 에러 발생한다(liv3 에러)
상수는 constant pool이라는 곳에서 따로 관리된다(메서드가 종료돼도 constant pool에 상수가 남아있다 => 메서드가 종료되어도 사용 할 수 있다)
public class Outer {
private int outerIv = 0;
static int outerCv = 0;
// private static int outerCv = 0; // private 붙여도 가능
class InstanceInner {
int iiv = outerIv; // 1. 외부 클래스의 private 멤버도 접근가능
int iiv2 = outerCv;
}
static class StaticInner {
// int siv = outerIv; // static 클래스는 외부 클래스의 인스턴스 멤버에 접근할 수 없다
static int scv = outerCv;
}
void myMethod() {
int lv = 0; // 변수, 값이 바뀌지 않는 변수는 상수로 간주
final int LV = 0; // 상수, JDK 1.8부터 final 생략 가능
lv = 3;
class LocalInner { 2. 지역 내부 클래스를 감싸고 있는 메서드의 상수만 사용가능
int liv = outerIv;
int liv2 = outerCv;
// 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다(JDK 1.8 이후부터 에러아님)
int liv3 = lv; // 에러, 변수 3으로 바뀜
int liv4 = LV;
}
}
}
외부 클래스의 밖에서 내부 클래스 사용방법
class Outer2 {
class InstanceInner { // 내부 클래스
int iv = 100;
}
static class StaticInner {// 내부 클래스
int iv = 200;
static int cv = 300;
}
void myMethod() { // 내부 클래스
class LocalInner {
int iv = 400;
}
}
}
public class InnerOuter {
public static void main(String[] args) {
Outer2 oc = new Outer2(); // 외부 클래스의 인스턴스를 먼저 생성해야 인스턴스 클래스의 멤버 사용 가능
Outer2.InstanceInner ii = oc.new InstanceInner();
System.out.println(ii.iv); // 100
System.out.println(Outer2.StaticInner.cv); // 300
// static 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다
Outer2.StaticInner si = new Outer2.StaticInner(); // 외부 클래스(Outer2)의 이름은 붙여줘야 한다
System.out.println(si.iv); // 200
}
}
100
300
200
이름이 같을 경우 구별방법
class Outer3 {
int value = 10; // Outer3.this.value value: 외부 클래스의 iv
class Inner {
int value = 20; // this.value value: 내부 클래스 iv
void method1() {
int value = 30; // lv 지역변수
System.out.println(value); // 30
System.out.println(this.value); // 20
System.out.println(Outer3.this.value);// 10
}
}
}
public class InnerSameName {
public static void main(String[] args) {
Outer3 outer = new Outer3();
Outer3.Inner inner = outer.new Inner();
inner.method1();
}
}
30
20
10
'Java > JAVA2' 카테고리의 다른 글
printStackTrace(), getMessage() (0) | 2023.06.22 |
---|---|
예외 처리하기, try-catch문 (0) | 2023.06.20 |
프로그램 오류, 예외 클래스의 계층구조 (0) | 2023.06.19 |
익명 클래스(anonymous class) (0) | 2023.06.19 |
내부 클래스(inner class) (0) | 2023.06.17 |