public class Class {
static class MemberClass { ... }
}
public class Class {
void method() {
class LocalClass { ... }
}
}
void method() {
class DownloadThread extends Thread { ... }
DownloadThread thread = new DownloadThread();
thread.start();
}
package com.company.nested_class;
public class OuterClass {
public String instanceField = "instanceField";
public static String staticField = "staticField";
class InnerClass {
String innerClassInstanceField = instanceField;
String innerClassStaticField = staticField;
public void innerClassMethod() {
System.out.println(instanceField);
System.out.println(staticField);
}
/**
* ERROR: 일반 중첩 클래스는 내부에서 정적인 메소드 선언이 불가능하다.
*
* WHY: 중첩 클래스는 외부 클래스 생성 전에는 생성되지 않기 때문에
* JVM 메모리 중 메소드 영역에 상주해야 하는 static 을 사용할 수 없다.
*/
// public static void innerClassStaticMethod() {
//
// }
}
static class StaticInnerClass {
/**
* ERROR: 정적 중첩 클래스에서는 인스턴스 변수의 이용이 불가능하다.
*
* WHY: 외부 클래스의 인스턴스 멤버란 것은 외부 클래스가 객체화 되어야
* 실제적인 주소를 갖는다. 그런데, static 영역은 그 주소를 갖기 전에 초기화된다.
*/
// String staticInnerClassField = instanceField;
String staticInnerClassStaticField = staticField;
public void staticInnerClassMethod() {
// System.out.println(instanceField);
System.out.println(staticField);
}
public static void staticInnerClassStaticMethod() {
// System.out.println(instanceField);
System.out.println(staticField);
}
}
void outerMethod(final int arg1, int arg2, String fs) {
final int var1 = 1;
int var2 = 2;
class LocalClass {
void method() {
// 아래의 코드로 인해 사실상 모두 final 로 변경됨
int result = arg1 + arg2 + var1 + var2;
}
}
/**
* ERROR: 로컬 클래스에서 사용된 메소드 파라미터 및 매개변수는
* final 효과를 가져 수정할 수 없다.
*
* WHY: 클래스의 메소드 내부에서 생성된 로컬 클래스의 객체는
* 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용할 수 있다.
* 반면에 메소드 블록에 존재하는 변수나 매개변수들은 메소드 실행이 끝나면,
* 스택에서 제거되어 더이상 사용할 수 없게 된다.
* final 로 이루어진 상수를 참조하는 것은 스택 메모리 영역을 사용하지 않아 괜찮은데,
* 변수를 참조하면 해당 메모리 영역 자체가 스택에서 지워지기 때문에 안된다.
*/
// arg2 = 10000;
}
}
public class OuterClass {
String field = "Outter-field";
Class NestedClass {
void printOuterField() {
System.out.println(OuterClass.this.field);
}
}
}
public class Button {
OnClickListener listener; // 인터페이스 타입 필드
void setOnClickListener(OnClickListener listener) {
this.listener = listener; // 매개변수의 다형성
// OnClickListener인터페이스를 상속하는 객체를 받을 수 있다.
}
// 터치 시 구현 객체의 메소드 호출
void touch() {
listener.onClick();
}
// 중첩 인터페이스
interface OnClickListener {
void onclick();
}
}
public class CallListener implements Button.OnclickListener {
@Override
public void onClick() {
System.out.println("전화를 겁니다.");
}
}
public class ButtonExample {
public static void main(String[] args) {
Button btn = new Button();
btn.setOnClickListener(new CallListener());
btn.touch();
btn.setOnClickListener(new MessageListener());
btn.touch();
}
}
public class Parent {
int parentField = 0;
public void parentMethod() {
System.out.println("parentMethod called");
}
}
public class Main {
public static void main(String[] args) {
Parent parent = new Parent() {
@Override
public void parentMethod() {
System.out.println("It's anonymous object");
System.out.println("parentField = " + parentField);
}
};
parent.parentMethod();
}
}
public interface Button {
void onClick();
}
public class Main {
public static void main(String[] args) {
Button button = new Button() {
@Override
public void onClick() {
System.out.println("클릭됨");
}
};
button.onClick();
}
}
public class Main {
public void method(int arg1) {
int localVariable = 10;
Button button = new Button() {
@Override
public void onClick() {
System.out.println("localVariable = " + localVariable);
System.out.println("arg1 = " + arg1);
}
};
// localVariable = 20;
// arg1 = 20;
}
}
public class Main {
public void method(int arg1) {
int localVariable = 10;
Button button = new Button() {
// 메소드 로컬 변수를 익명 객체 내부의 필드로 복사함
int anonymousClassLocalVariable = localVariable;
@Override
public void onClick() {
// 에러
localVariable = 20;
// 정상적인 수행 가능
anonymousClassLocalVariable = 20;
System.out.println("localVariable = " + localVariable);
System.out.println("arg1 = " + arg1);
}
};
}
}