java 공부중
public class NestedOuter {
private static int outClassValue = 3;
private int outInstanceValue = 2;
static class Nested {
private int nestedInstanceValue = 1;
public void print() {
// 자신의 멤버에 접근
System.out.println(nestedInstanceValue);
// 바깥 클래스의 인스턴스 멤버에는 접근 불가능.
//System.out.println(outInstanceValue);
// 바깥 클래스의 클래스 멤버에는 접근 가능. private도 접근 가능
System.out.println(NestedOuter.outClassValue);
}
}
}
// 인스턴스 생성할 때
public static void main(String[] args) {
NestedOuter outer = new NestedOuter();
NestedOuter.Nested nested = new NestedOuter.Nested();
nested.print();
System.out.println("nestedClass = " + nested.getClass());
}
public class InnerOuter {
private static int outClassValue = 3;
private int outInstanceValue = 2;
class Inner {
private int innerInstanceValue = 1;
public void print() {
// 자신의 멤버에 접근
System.out.println(innerInstanceValue);
// 외부 클래스의 인스턴스 멤버에 접근 가능, private도 접근 가능
System.out.println(outInstanceValue);
// 외부 클래스의 클래스 멤버에는 접근 가능. private도 접근 가능
System.out.println(InnerOuter.outClassValue);
}
}
}
// 인스턴스 생성할 때
public static void main(String[] args) {
InnerOuter outer = new InnerOuter();
//인스턴스값을 참조해야하기 때문에 인스턴스 생성 후 outer.new Inner()로 내부 클래스가 생성되어야함.
InnerOuter.Inner inner = outer.new Inner();
inner.print();
System.out.println("innerClass = " + inner.getClass());
}

만약 바깥 클래스와 내부 클래스가 같은 이름의 변수를 가지면 어떻게 할까?
public class ShadowingMain {
public int value = 1;
class Inner {
public int value = 2;
void go() {
int value = 3;
System.out.println("value = " + value); // 3
System.out.println("this.value = " + this.value); //2
System.out.println("ShadowingMain.value = " +
ShadowingMain.this.value); // 1
}
}
public static void main(String[] args) {
ShadowingMain main = new ShadowingMain();
Inner inner = main.new Inner();
inner.go();
}
}
public class LocalOuterV1 {
private int outInstanceVar = 3;
public void process(int paramVar) {
int localVar = 1;
class LocalPrinter { // 지역 클래스에 접근 제어자 사용 불가능.
int value = 0;
public void printData() {
System.out.println("value=" + value);
System.out.println("localVar=" + localVar);
System.out.println("paramVar=" + paramVar); //파라미터도 지역변수에 포함됨.
System.out.println("outInstanceVar=" + outInstanceVar);
}
}
LocalPrinter printer = new LocalPrinter();
printer.printData();
}
//인스턴스 생성
public static void main(String[] args) {
LocalOuterV1 localOuter = new LocalOuterV1();
localOuter.process(2);
}
}
public class LocalOuterV3 {
private int outInstanceVar = 3;
public Printer process(int paramVar) {
int localVar = 1; //지역 변수는 스택 프레임이 종료되는 순간 함께 제거된다.
class LocalPrinter implements Printer {
int value = 0;
@Override
public void print () {
System.out.println("value=" + value);
//인스턴스는 지역 변수보다 더 오래 살아남는다.
System.out.println("localVar=" + localVar);
System.out.println("paramVar=" + paramVar);
System.out.println("outInstanceVar=" + outInstanceVar);
}
}
Printer printer = new LocalPrinter();
//printer.print()를 여기서 실행하지 않고 Printer 인스턴스만 반환한다.
return printer;
}
public static void main(String[] args) {
LocalOuterV3 localOuter = new LocalOuterV3();
Printer printer = localOuter.process(2);
//printer.print()를 나중에 실행한다. process()의 스택 프레임이 사라진 이후에 실행
printer.print();
}
}
위의 코드를 실행하면 아래와 같은 결과가 나온다.
value=0
localVar=1
paramVar=2
outInstanceVar=3


근데 여전히 변수가 출력이 되는 이유는 인스턴스를 생성할 때 지역 변수를 캡처해두기때문이다.
지역 변수 캡처해두고 나서 지역 변수의 값을 변경하면 동기화문제가 생기는데 이를 방지하기 위해서 지역 클래스가 접근하는 지역변수는 절대로 값이 변하면 안된다. 그래서 final을 적어주거나 사실상 final이다. (final을 안적어도 final처리됨)
지역 클래스 중 하나로 클래스의 이름이 없음
기존 클래스: 선언과 생성을 별도로 진행
익명 클래스: 클래스 이름 생략하여 선언과 생성을 한번에 처리
부모 클래스를 상속받거나, 인터페이스를 구현해야함. 익명 클래스는 상위 클래스나 인터페이가 필요.
생성자 가질 수 없고, 기본 생성자만 사용됨.
클래스를 별도 정의하지 않고도 인터페이스나 추상 클래스를 즉석에서 구현할 수 있어서 간결해지지만 복잡하거나 재사용이 필요한 경우는 별도 클래스를 정의하는게 좋음.
// Printer라는 인터페이스가 있다 치고
public class AnonymousOuter {
private int outInstanceVar = 3;
public void process(int paramVar) {
int localVar = 1;
//익명 클래스
Printer printer = new Printer() {
int value = 0;
@Override
public void print() {
System.out.println("value=" + value);
System.out.println("localVar=" + localVar);
System.out.println("paramVar=" + paramVar);
System.out.println("outInstanceVar=" + outInstanceVar);
}
};
printer.print();
System.out.println("printer.class=" + printer.getClass());
}
public static void main(String[] args) {
AnonymousOuter main = new AnonymousOuter();
main.process(2);
}
}