중첩 클래스
클래스 내부에 선언한 클래스
중첩 클래스
class ClassName{
class NestedClassName{
}
}
중첩 인터페이스
class ClassName{
interface NestedInterfaceName{
}
}
선언 위치에 따른 분류 | 선언 위치 | 설명 | |
멤버 클래스 |
인스턴스 멤버 클래스 |
class A{ class B{...} } |
A 객체를 생성해야만 사용할 수 있는 B 클래스 |
정적 멤버 클래스 |
class A{ static class B{...} } |
A 클래스로 바로 접근할 수 있는 B 클래스 |
|
로컬 클래스 |
class A{ void method(){ class B{...} } } |
method()가 실행할 때만 사용할 수 있는 B 클래스 |
인스턴스 멤버 클래스
A 클래스 내부 중첩 클래스인 B 클래스의 객체 생성 법
A 클래스 내부
public class A{
class B{
int field;
void method(){};
}
B b = new B();
b.field = 3;
b.method();
}
A 클래스 외부
public class Test{
public static void main(String[] args){
A a = new A();
A.B b =a.new B();
b.field = 4;
b.method();
}
}
대부분 A클래스 내부에서 사용
정적 멤버 클래스
A 클래스 외부에서 사용한데도 A객체를 생성할 필요X
public class A{
static class B{
int field1;
static int field2;
void method1(){};
static void method2(){};
}
}
public class Test{
public static void main(String[] args){
A.B b = new A.B();
b.field1 = 4;
b.method1();
A.B.field2 = 3;
A.B.method2();
}
}
로컬 클래스
public class A{
void methodA(){
class B{
int field1;
void method1(){};
}
B b = new B();
b.field1 = 5;
b.method1();
}
}
바깥 필드와 메소드에서 사용 제한
인스턴스 멤버 클래스(B)는 바깥 클래스의 인스턴스 필드의 초기값이나 인스턴스 메소드에서만 객체 생성 가능
정적 멤버 클래스(C)는 모든 필드의 초기값이나 모든 메소드에서 객체 생성 가능
public class A{
class B{}//인스턴스 멤버 클래스
static class C{}//정적 멤버 클래스
B field1 = new B();//인스턴스 필드
C field2 = new C();//인스턴스 필드
//static B field3 = new B(); ERROR 정적 필드
static C field4 = new C();//정적 필드
void method1(){//인스턴스 메소드
B var1 = new B();
C var2 = new C();
}
static void method2(){//정적 메소드
//B var1 = new B(); ERROR
C var2 = new C();
}
}
멤버 클래스에서 사용제한
인스턴스 멤버 클래스(B) 안에서는 바깥 클래스의 모든 필드와 메소드에 접근 가능
정적 멤버 클래스(C) 안에서는 정적 필드와 정적 메소드만 접근 가능
public class A{
int field1;//인스턴스 필드
void method1(){}//인스턴스 메소드
static int field2;//정적 필드
static void method2(){}//정적 메소드
public class B{//인스턴스 멤버 클래스
void method(){
field1 = 10;
method1();
field2 = 10;
method2();
}
}
static class C{//정적 멤버 클래스
void method(){
//field1 = 10; ERROR
//method1(); ERROR
field2 = 10;
method2();
}
}
}
로컬 클래스에서 사용제한
로컬 클래스는 메소드 안에 존재하기 때문에
그 메소드가 종료되면 사라지는게 일반적이지만
메소드가 종료되어도 계속 실행 상태로 존재할 수 있음(로컬 스레드 객체)
이때 자바는 로컬 클래스에서 사용하는
로컬 클래스를 포함하는 메소드의 매개변수 OR 로컬 변수값을
로컬 클래스 내부에 복사해두고 사용
그리고 매개변수나 로컬변수가 수정되어 값이 변경되면
로컬 클래스에 복사해둔 값과 달라지므로
매개변수나 로컬 변수는 final로 선언요구(자바 8이후에는 생략해도 붙음)
public class A{
void method1(int arg){
int localVal = 10;
arg = 100;
localVal = 20;
}
void method2(int arg){//final이 생략됐지만 자동 final
int localVal = 10;//final이 생략됐지만 자동 final
//arg = 100; ERROR
//localVal = 20; ERROR
class Inner{//로컬 클래스
void method(){
int result = arg+localVal;
}
}
}
}
중첩 클래스에서 바깥 클래스 참조 얻기
중첩 클래스에서 바깥 클래스의 객체 참조
바깥클래스.this.필드
바깥클래스.this.메소드();
public class A{
String field = "바깥 클래스 필드";
void method(){
System.out.println("바깥 클래스 메소드");
}
class B{
String field = "중첩 클래스 필드";
void method(){
System.out.println("중첩 클래스 메소드");
}
void print(){
System.out.println(this.field);//중첩 객체 참조
this.method();//중첩 객체 참조
System.out.println(A.this.field);//바깥 객체 참조
A.this.method();//바깥 객체 참조
}
}
}
public class Test{
public static void main(String[] args){
A a = new A();
A.B b = a.new B();
b.print();
}
}
중첩 인터페이스
클래스의 멤버로 선언된 인터페이스
class A{
interface I{
void method();
}
}
해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해
인스턴스 멤버 인터페이스와 정적 멤버 인터페이스 둘 다 가능
주로 정적 멤버 인터페이스 사용
예제)
Button을 클릭했을 때 이벤트를 처리하는 객체를 받고 싶다
Button 내부에 선언된 중첩 인터페이스를 구현한 객체만 맏고 싶다
Button 클래스와 중첩 인터페이스 OnClickListener
public class Button{
static interface OnClickListener{//중첩 인터페이스
void onClick();
}
OnClickListener listener;//인터페이스 타입 필드
void setOnClickListener(OnClickListener listener){//매개변수의 다형성
this.listener = listener;
}
void touch(){
listener.onClick();//구현 객체의 onClick메소드 호출
}
}
구현 객체1 CallListener
public class CallListener implements Button.OnClickListener{
@Override
public void onClick(){
System.out.println("전화를 겁니다.");
}
}
구현 객체2 MessageListener
public class MessageListener implements Button.OnClickListener{
@Override
public void onClick(){
System.out.println("메세지를 보냅니다");
}
}
실행 클래스 ButtonTest
public class ButtonTest{
public static void main(String[] args){
Button btn = new Button();
btn.setOnClickListener(new CallListener());
btn.touch();
btn.setOnClickListener(new MessageListener());
btn.touch();
}
}