(CF) 어플개발할때 이너클래스 자주 사용한다
보통은 하나의 자바파일을 정의할때 하나의 클래스만 선언하는 경우가 많음
이너클래스 말고 클래스 바깥 다른곳에도 클래스를 또 정의할 수 있는데 그럼 두 클래스는 그냥 동시에 존재하고 있는거다~ 두번째 클래스는 public 못붙이고 걍 class 클래스명임! (일반적 X)
혀튼 많이 쓰는건 아니고... 그냥 클래스는 다양한곳에 선언 할 수 있다는 개념을 알도록 하자
중첩클래스란? 클래스 내부에 선언한 클래스. 사용시 두 클래스 멤버들을 서로 쉽게 접근 할 수 있게 하고 외부에는 불필요한 관계클래스를 감춤으로서 코드의 복잡성을 줄일 수 있다.
인터페이스도 클래스 내부에 선언 할 수 있는데, 이를 중첩인터페이스 라고 한다. 사용하는 이유는 해당 클래스와 긴밀한 관계를 갖는 구현 클래스를 만들기 위해서이다.
- 멤버클래스의 경우 바이트코드파일의 이름
A $ B .class
- 로컬클래스의 경우 바이트코드파일의 이름
A $1 B .class
class A {
class B{
B(){...}
int field1;
//static int field2; << static 사용불가
void method1() {}
//static void method2() {} << static 사용불가
}
}
A클래스 외부에서 B객체를 생성하려면 A객체부터 생성 하고 B객체를 생성해야한다.
A클래스 내부의 생성자 및 인스턴스 메소드에서는 일반클래스처럼 B객체를 생성 할 수 있다.
[A클래스 외부]
A a = new A(); << A부터 생성
A.B b = a.new B();
b.field1 = 3;
b.method1();
[A클래스 내부]
class A {
class B{
void methodA() {}
B b = new B();
b.field1 = 3;
b.method1();
}
}
일반적으로 외부에서 생성하는 일은 거의 없고 A클래스 내부에서 B객체 생성하는게 대부분
class A {
static class C {
C() { } << 생성자
int field1; << 인스턴스필드
static int field2; << 정적필드
void method1() {} << 인스턴스메소드
static void method2 {} << 정적메소드
}
}
A클래스 외부에서 정적멤버클래스 C의 객체를 생성하기 위해서는 A객체를 생성 할 필요가 없고 C를 생성
A.C c = new A.C();
c.field1 = 3;
c.method();
A.C.field2=3;
A.C.method2 ();
void method() {
class D{
D() {}
int field1;
//static int field2;
void method1() {}
//static void method2() {}
}
D d = new D();
d.field1 = 3;
d.method1();
}
주로 다음과같이 미동기 처리를 위한 스레드 객체를 만들 때 사용한다.
void method() {
class DownloadThread extends Thread {...}
DownloadThread thread = new DownloadThread();
thread.start();
}
// 바깥클래스
class A {
A() {System.out.println("A객체가 생성됨");}
//인스턴스멤버클래스
class B {
B() {System.out.println("B객체가 생성됨");}
int field1;
// static int field2;
void method1() {}
// void method2() {}
}
//정적멤버클래스
static class C {
C() {System.out.println("C 객체가 생성됨");}
int field1;
static int field2;
void method1() {}
static void method2() {}
}
void method() {
//로컬클래스
class D {
D(){System.out.println("D 객체가 생성됨");}
int field1;
// static int field2;
void method1() {}
//static void method2() {}
}
D d = new D();
d.field1 = 3;
d.method1();
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
// 인스턴스멤버클래스 객체생성
A.B b = a.new B();
b.field1 = 3;
b.method1();
//정적 멤버 클래스 객체 생성
A.C c = new A.C();
c.field1 = 3;
c.method1();
A.C.field2 = 3;
A.C.method2();
//로컬클래스 객체 생성을 위한 메소드 호출
a.method();
}
}
인스턴스멤버 클래스(B)는 바깥클래스의 인스턴스(field1)의 초기값이나
인스턴스메소드(method1())에서 객체를 생성 할 수 있으나
정적필드(field3)의 초기값이나 정적메소드(method2())에서는 객체를 생성 할 수 없다
반면, 정적멤버클래스(C)는 모ㅗ든필드의 초기값이나 모든 메소드에서 객체 생성 가능
public class A {
// 인스턴스 필드
B field1 = new B();
C field2 = new C();
// 인스턴스 메소드
void method1(){
B var1 = new B();
C var2 = new C();
}
// 정적 필드 초기화
//static B field3 = new B();
static C field4 = new C();
// 정적메소드
static void method2() {
//B car1 = new B();
C var2 = new C();
}
//인스턴스멤버클래스
class B():
//정적멤버클래스
static class C();
public class Outter{
public void method1(final int arg){
//arg = 100;
//localVariable = 100;
class Inner{
public void method() {
int result = arg + localVariable; //매개변수와 로컬변수를 로컬클래스 내부에서 사용할때 final특성을 갖고있음을 알 수 있다
}
}
}
}
// 자바8 이후부터는 final 생략해서 써도 ㄱㅊ
public class Outter {
String field = "Outter-field";
void method() {
System.out.println("Outter-method");
}
class Nested {
String field = "Nested-field";
void method() {
System.out.println("Nested-method");
}
void print() {
System.out.println(this.field);
this.method();
System.out.println(Outter.this.field);
Outter.this.method();
}
}
public class OutterExample {
public static void main(String[] args) {
Outter outter = new Outter();
Outter.Nested nested = outter.new Nested();
nested.print();
}
}
class A {
[static] interface I {
void method();
}
}
버튼 클릭시 이벤트를 처리하는 객체를 받는다고 가정,
버튼 내부에 선언된 중첩 인터페이스를 구현한 객체만 받아야한다.
public class Button {
OnClickListener listener; // 중첩인터페이스 타입으로 필드를 선언
void setOnClickListener(OnClickListener listener) {
this.listener = listener; // 구현객체를 받아 필드에 대입
}
void touch() {
listener.onClick();
}
static interface OnClickListener {
void onClick(); // 버튼이벤트(touch()실행시) 발생시 인터페이스를 통해 구현객체의
//메소드 호출
}
}
//구현클래스
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 ButtonExample {
public static void main(String[] args) {
Button btn = new Button();
btn.setOnClickListener(new CallListener());
btn.touch();
btn.setOnClickListener(new MessageListener());
btn.touch();
}
}
일회용객체 느낌
인터페이스였던 리모트컨트롤과 그 구현객체인 오디오 등이 있을때
오디오는 오디오라는 잌름이있음
new Remotecontrol(){
@Override
public void turnOn(){
}
@Override
public void turnOff(){
}
}
이런식으로 이름이 없지만 메소드를 재정의 할 수 있다
오디오나 티비는 계속 쓸라고 클래스 정의 했는데, 위의 경우 걍 생산과 동시에 사용하고 .. control변수 사라지면 저 코드는 이제 의미없어지는거... ㄹㅇ로 한번쓰고 버림
편할라고 쓰는거임
인터페이스 A에 void method1();이 있을때,
A를 상속받는 객체르 만들수도 있지만 익명개체를 쓸수도 있다
구현받는 바디가 없으니까... 구현체가 있어야 생성이 되겠지
new A() { void method1(); } 이렇게 오버라이드해서 사용하면 된다
익명개체의 조건 : 어떤 클래스를 상속하거나 인터페이스를 구현해야한다.
[상속]
class 클래스이름1 extends 부모클래스 {...}
부모클래스 변수 = new 클래스이름1();
// 위와같이 상속을 처리했으나 익명객체는 클래스 이름이 없으므로
**부모클래스 변수 = new 부모클래스() {...};
// 부모클래스는 이름이 없는 자식 객체를 참조**
[구현]
class 클래스이름2 implements 인터페이스 {...}
인터페이스 변수 = new 클래스이름2();
// 마찬가지로 클래스이름이 없으므로
**인터페이스 변수 = new 인터페이스() {...}
// 이름이 없는 구현객체를 참조**
class Child extends Parent { } // 부모클래스 상속한 자식클래스 선언
class A {
Parent field = new Child(); // 필드에 자식객체 대입
void method() {
Parent localVar = new Child(); // 로컬변수에 자식객체 대입
}
}
부모클래스 [필드|변수] = new 부모클래스(매개값, ...) {
//필드 (오버라이딩)
//메소드 (오버라이딩)
};