중첩 클래스 : 클래스 내부에 선언되는 클래스
중첩 인터페이스 : 클래스 내부에 선언되는 인터페이스
중첩 클래스
인스턴스 멤버 클래스 | class A { class B{..} } |
A 객체 생성해야만 사용 가능 인스턴스 필드, 메소드만 선언 가능 |
정적 멤버 클래스 | class A { static class B{..} } |
A클래스로 바로 접근 가능 모든 종류 필드, 메소드 선언 가능 |
로컬 클래스 | class A { void method(){ class B{..} } } |
메소드 내부에서만 사용됨 => 접근제한자, static 붙일 수 없음 인스턴스 필드, 메소드만 선언 가능 |
public class ClassA { //외부 클래스
int fieldA;
public ClassA() {
System.out.println("ClassA가 생성됨");
}
void methodA() {
//로컬 클래스 (외부클래스의 메소드 내 클래스)
class ClassD {
int fieldD;
public ClassD() {
System.out.println("메서드 안에 있는 로컬클래스 ClassD가 생성됨");
}
void methodD() {}
}
}
//인스턴스 내부 클래스 => 인스턴스 필드, 메서드만 선언 가능
class ClassB{
int fieldB;
//static int fieldB2;
public ClassB() {
System.out.println("ClassB가 생성됨");
}
void methodB() {}
}
//정적 내부 클래스 => 모든 종류 필드, 메서드 선언 가능
static class ClassC{
int fieldC;
static int fieldC2;
public ClassC() {
System.out.println("ClassC가 생성됨");
}
void methodC() {}
static void methodC2() {}
}
}
- 내부 인스턴스 클래스
public class NestedClassEx1 {
public static void main(String[] args) {
ClassA a = new ClassA(); //ClassA 객체 생성
a.fieldA=30;
a.methodA();
//ClassA의 내부클래스 생성(반드시 외부 클래스 생성된 후)
ClassA.ClassB b = a.new ClassB(); //ClassB 객체 생성
b.fieldB=50;
b.methodB();
}
}
- 내부 정적 클래스
public class NestedClassEx2 {
public static void main(String[] args) {
//내부 정적 클래스 객체 생성 => 외부클래스 객체 필요 X
ClassA.ClassC c = new ClassA.ClassC();
c.fieldC=30; //인스턴스 필드, 메소드
c.methodC();
ClassA.ClassC.fieldC2=50; //정적 필드, 메소드
ClassA.ClassC.methodC2();
}
}
- 로컬 클래스 : 외부클래스 메소드 안에서만 생성, 사용 가능
public class ClassA {
int fieldA;
public ClassA() {
System.out.println("ClassA가 생성됨");
}
void methodA() {
//로컬 클래스
class ClassD {
int fieldD;
public ClassD() {
System.out.println("메서드 안에 있는 로컬클래스 ClassD가 생성됨");
}
void methodD() {}
}
ClassD d = new ClassD(); //
d.fieldD=60; //
d.methodD(); //
}
}
중첩클래스의 접근 제한
- 외부클래스에서 사용 제한
인스턴스 멤버클래스 : 외부클래스의 인스턴스 필드, 메소드에서만 초기화 & 객체 생성 가능
정적 멤버클래스 : 모든 필드에서 초기화, 모든 메소드에서 객체 생성 가능
public class ClassA {
class ClassB{} //인스턴스 멤버클래스
static class ClassC{} //정적 멤버클래스
//인스턴스 필드
ClassB field1 = new ClassB();
ClassC field2 = new ClassC();
//인스턴스 메소드
void method1() {
ClassB mtd1 = new ClassB();
ClassC mtd2 = new ClassC();
}
//정적 필드
//static ClassB field3 = new ClassB(); //인스턴스 멤버클래스 => 외부 정적 필드 초기화 X
static ClassC field4 = new ClassC();
//정적 메소드
static void method2(){
//ClassB mtd1 = new ClassB(); //인스턴스 멤버클래스 => 외부 정적 메소드에서 객체 생성 X
ClassC mtd2 = new ClassC();
}
}
- 멤버클래스에서 사용 제한
인스턴스 멤버클래스 : 외부 클래스의 모든 필드, 메소드 접근 가능
정적 멤버클래스 : 외부 클래스의 정적 필드, 메소드에만 접근 가능
public class ClassA {
//인스턴스 필드
int field1;
void method1(){}
//정적 필드
static int field2;
static void method2(){}
//인스턴스 내부 클래스
class ClassB{
void method() {
field1 = 5;
method1();
field2=10;
method2(); //인스턴스 멤버클래스 => 모든 필드, 메소드 접근 가능
}
}
//정적 내부 클래스
static class ClassC{
void method() {
//field1 = 5; //정적 멤버클래스 => 인스턴스 메소드, 필드 접근 X
//method1();
field2=10;
method2();
}
}
}
- 로컬클래스에서 사용 제한
외부 클래스의 필드, 메소드 모두 사용 가능
메소드 실행이 끝나면 메소드 매개변수/로컬변수가 스택메모리에서 사라지는 것을 방지하기 위해 로컬클래스 내부에 복사해두고 사용 & final 선언
=> 로컬클래스에서는 final 매개변수, 로컬변수만 사용 가능 (선언 안 해도 final 특성 가짐)
public class Outer {
public void method2(int num){ //num: 매개변수
int localVariable=1; //localVariable: 로컬변수
//num=10; //값 변경 불가
//localVariable = 10; //값 변경 불가
class Inner{
public void method(){
int result = num + localVariable; //모든 변수 final 특성
}
}
}
}
- 중첩클래스에서 외부클래스 참조 얻기
중첩클래스 내부에서 this.필드/메소드 => 중첩클래스의 필드/메소드 사용
외부클래스.this.필드/메소드 => 외부클래스 필드/메소드 사용
중첩 인터페이스
class A {
interface I {
void method();
}
}
- ex
public class Button {
//인터페이스 타입 필드
OnClickListener listener;
//메서드(매개변수의 다형성)
void setOnClickListener(OnClickListener listener) { //매개변수로 인터페이스 받음
this.listener=listener;
}
//메서드
void touch() {
listener.onClick();
}
//중첩 인터페이스
interface OnClickListener{
void onClick(); //추상메소드
}
}
//구현 클래스
public class CallListener implements Button.OnClickListener{
@Override
public void onClick() {
System.out.println("전화를 겁니다");
}
}
//구현 클래스
public class MessageListener implements Button.OnClickListener{
@Override
public void onClick() {
System.out.println("문자를 합니다");
}
}
public class ButtonEx1 {
public static void main(String[] args) {
Button btn = new Button(); //인스턴스 객체 생성
btn.setOnClickListener(new CallListener());
btn.touch();
btn.setOnClickListener(new MessageListener());
btn.touch();
}
}
//
전화를 겁니다
문자를 합니다
익명 객체
: 이름이 없는 객체
단독 생성 X / 상속 or 인터페이스 구현해야 생성됨
필드의 초기값, 로컬변수의 초기값, 매개변수의 매개값으로 주로 대입됨
끝에 세미콜론
생성자 선언 불가
익명 자식 객체에서 새로 정의된 필드, 메소드는 내부에서만 사용 가능
- (상속) 익명 자식 객체 생성
//필드 선언
//class Child extends Parent {}
//
//class A {
// Parent field = new Child(); //필드에 자식객체 대입
// void method(){
// Parent localVar = new Child(); //로컬변수에 자식객체 대입
// }
//}
//필드 선언 시 초기값으로 익명자식객체 대입
class A {
void method(){
Parent localVar = new Parent(){ //익명 자식 객체 생성, 대입
int childField;
void childMethod();
@Override
void parentMethod(){} //부모클래스 메소드 오버라이딩
};
}
}
//메소드 매개변수가 부모타입일 때, 매개값으로 익명자식객체 대입
class A {
void method1(Parent parent){}
void method2(){
method1(
new Parent(){ //method1 매개값으로 익명 자식 객체 대입
int childField;
void childMethod();
@Override
void parentMethod(){}
}
);
}
}
public class Person {
void wake() {
System.out.println("7시에 일어납니다");
}
}
public class Anonymous {
Person pField=new Person() { //필드에 대입
void walk() {
System.out.println("산책합니다");
}
@Override
void wake() {
System.out.println("6시에 일어납니다");
walk();
}
};
//메서드
void method1(Person person) { //매개값으로 대입
person.wake();
}
void method2() {
Person localPerson = new Person() { //로컬변수에 대입
void study() {
System.out.println("공부합니다");
}
void wake() {
System.out.println("7시에 일어납니다");
study();
}
};
localPerson.wake(); //로컬변수 사용
}
}
public class AnonymousEx1 {
public static void main(String[] args) {
Anonymous anon = new Anonymous(); //인스턴스 객체 생성
anon.pField.wake(); //필드 대입
anon.method1(new Person() { //매개값 대입
void work() {
System.out.println("출근합니다");
}
@Override
void wake() {
System.out.println("8시에 일어납니다");
work();
}
});
anon.method2(); //로컬변수 대입
}
}
//
6시에 일어납니다
산책합니다
8시에 일어납니다
출근합니다
7시에 일어납니다
공부합니다
- (인터페이스) 익명 구현 객체 생성
public interface RemoteControl {
void turnOn();
void turnOff();
}
public class Anonymous {
//필드 초기값으로 대입
RemoteControl TV = new RemoteControl() {
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
}
};
void method1(){
//로컬 변수값으로 대입
RemoteControl audio = new RemoteControl() {
@Override
public void turnOn() {
System.out.println("오디오를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("오디오를 끕니다.");
}
};
//로컬 변수 사용
audio.turnOn();
audio.turnOff();
}
//매개값으로 대입 (예정)
void method2(RemoteControl remoteControl){
remoteControl.turnOn();
remoteControl.turnOff();
}
}
public class AnonymousEx {
public static void main(String[] args) {
Anonymous an = new Anonymous();
//익명 객체 필드 사용
an.TV.turnOn();
an.TV.turnOff();
//익명 객체 메소드 사용
an.method1();
//매개변수로 익명 객체 대입
an.method2(new RemoteControl() {
@Override
public void turnOn() {
System.out.println("자동차를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("자동차를 끕니다.");
}
});
}
}
//
TV를 켭니다.
TV를 끕니다.
오디오를 켭니다.
오디오를 끕니다.
자동차를 켭니다.
자동차를 끕니다.
'Programming > 자바' 카테고리의 다른 글
자바 재정리 - API (0) | 2022.09.05 |
---|---|
자바 재정리 - 예외 처리 (0) | 2022.08.26 |
자바 재정리 - 인터페이스 (0) | 2022.08.25 |
자바 재정리 - 상속 (0) | 2022.08.23 |
자바 재정리 - 클래스 (0) | 2022.08.11 |