9. 중첩 선언과 익명개체
9.1 중첩클래스
중첩? 클래스안에 클래스 클래스안에 인터페이스 선언이 있을 수 있다.
익명개체 이름이 없는 객체
중첩클래스는 클래스 선언안에 도 다른 클래스 선언 을 말한다.
class A{class B{}} 등 사진참조
멤버클래스 클래스 블록에 선언함. 필드 생성자 메소드 처럼
인스턴스 멤버클래스 : a객체가 잇어야 b사용가능 정적 멤버클래스 a가없어도 b를 생성가능
로컬클래스 매소드나생성자 안에 있는데 이 메소드를 실행할때만 존재하는 클래스임.
멤버클래스를 컴파일하면 A $ B.class로 나옴. 바깥클래스 $ 멤버클래스
로컬클래스면 A $1 B .class
9.2 인스턴스 멤버 클래스
인스턴스 멤버클래스는 다음과 같이 A클래스의 멤버로 선언된 B클래스를 말한다.
접근제한자에 따른 인스턴스 멤버 클래스의 접근 범위는 다음과 같다.
public class B{} 다른패키지에서 B클래스를 사용할 수 있다.
class B{} 같은 패키지에서만 B클래스를 사용할 수 있다.
private class B{} A클래스 내부에서만 B클래스를 사용할 수 있다.
B객체를 A크래스 외부에 생성하려면 default 또는 public 접근 제한을 가져야 하고
a객체를 생성한다음 b객체를 생성해야한다.
package ch09.sec02.exam02;
public class A {
//인스턴스 멤버클래스
class B{
//인스턴스 필드
int field1 = 1;
//정적필드(java 17부터 허용)
static int field2 = 2;
//생성자
B() {
System.out.println("B-생성자 실행");
}
//인스턴스 메소드
void method1(){
System.out.println("B-method1 실행");
}
//정적메소드(java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
// 인스턴스 메소드
void useB() {
B b = new B();
System.out.println(b.field1);
b.method1();
//B클래스의 정적 필드 및 메소드 사용
System.out.println(B.field2);
B.method2();
}
}package ch09.sec02.exam02;
public class Aexample {
public static void main(String[] args) {
// A객체 생성
A a = new A();
//A인스턴스 메소드 호출
a.useB();
}
} 
9.3 정적 멤버클래스
정적멤버클래스는 다음과 같이 static 키워드와 함께 a클래스의 멤버로 선언된 b클래스를 의미한다.
[public] class A{[public|private] static class B{}}
public static class B{} 다른 패키지에서 B클래스를 사용할 수 있다.
static class B{} 같은 패키지에서만 B클래스를 사용할 수 있다.
private static class B{} A클래스 내부에서만 B클래스를 사용할 수 있다.
package ch09.sec03.exam01;
public class A {
//인스턴스 멤버 클래스
static class B{
//인스턴스 필드
int field1 = 1;
//정적필드(java 17부터 허용)
static int field2 = 2;
//생성자
B() {
System.out.println("B-생성자 실행");
}
//인스턴스 메소드
void method1(){
System.out.println("B-method1 실행");
}
//정적메소드(java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
} package ch09.sec03.exam01;
public class AExample {
public static void main(String[] args) {
// B객체 생성 및 인ㅇ스턴스 필드 및 메소드 사용
A.B b = new A.B();
System.out.println(b.field1);
b.method1();
//b클래스의 정적필드 및 메소드사용
System.out.println(A.B.field2);
A.B.method2();
}
}9.4 로컬클래스
생성자 또는 메소드 내부에서 다음과 같이 선언된 클래스를 로컬 클래스라고 한다.
[public] class A{
// 생성자
public A(){
class B{}
}
//메소드
public void method(){
class B {}
} package ch09.sec04;
public class A {
//메소드
void useB() {
//로컬클래스
class B {
//인스턴스 필드
int field1 = 1;
//정적필드(java 17부터 허용)
static int field2 = 2;
//생성자
B() {
System.out.println("B-생성자 실행");
}
//인스턴스 메소드
void method1(){
System.out.println("B-method1 실행");
}
//정적메소드(java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
//로컬 객체 생성
B b = new B();
//로컬 객체의 인스턴스 필드와 메소드 사용
System.out.println(b.field1);
b.method1();
//로컬클래스의 정적 필드와 메소드사용(자바 17부터 허용)
System.out.println(B.field2);
B.method2();
}
}package ch09.sec04;
public class AExample {
public static void main(String[] args) {
// A객체 생성
A a = new A();
//A 메소드 호출
a.useB();
}로컬 변수(생성자 도는 메소드의 매개변수또는 내부에서 선언된 변수)를 로컬 클래스에서 사용할경우
로컬변수는 final 특성을 갖게 되므로 값을 읽을 수 만있고 수정할 수 없게 된다.
이것은 로컬크랠스 내부에서 값을 변경하지 못하도록 제한하기 때문이다.
java 8 이후부터는 명시적으로 final키워드를 붙이지 않아도 되지만
로컬변수에 final 키워들르 추가해서 final 변수임을 명확히 할수도 있다. 참고로 java7이전에는 무조건 붙여야햇음.
package ch09.sec04.exam02;
public class A {
//메소드
public void method1(int arg) { //final int arg
//로컬변수
int var = 1; //final int var = 1;
//로컬 클래스
class B{
//메소드
void method2() {
//로컬변수 읽기
System.out.println("arg: " + arg);
System.out.println("var: " + var);
//로컬변수 수정
//arg = 2; 불가능
//var = 2; 불가능
}
}
//로컬 객체 생성
B b = new B();
//로컬 객체 메소드 호출
b.method2();
//로컬변수 수정
//arg = 3; 불가능
//var = 3; 불가능
}
}9.5 바깥 멤버 접근
중첩클래스는 바깥 클래스와 긴밀한 관계를 맺으면서 바깥 클래스의 멤버(필드, 메소드)에 접글할 수 있다.
하지만 중첩클래스가 어떻게 선언되엇느냐에 따라 접근 제한이 잇을수있다.
9.5.1 바깥 클래스의 멤버 접근제한
정적멤버 클래스 내부에서는 바깥 크래스의 필드와 메서드를 사요할때 제한이 따른다.
인스턴스 멤버클래스 바깥 클래스의 모든 필드와 메소드
정적멤버 클래스 바깥클래스의 정적필드와 정적메소드
package ch09.sec05.exam01;
public class A {
//A의 인스턴스 필드와 메소드
int field1;
void method1() {}
//A의 정적필드와 메소드
static int field2;
static void method2() {}
//인스턴스 멤버 클래스
class B {
void method() {
//A의 인스턴스 필드와 메소드 사용
field1 = 10;
method1();
//A의 정적필드와 메소드 사용
field2 = 10;
method2();
}
}
//정적멤버 클래스
static class C {
void method() {
//A의 인스턴스 필드와 메소드 사용
//field1 = 10; 불가능
// method1(); 불가능
//A의 정적필드와 메소드 사용
field2 = 10; // 가능
method2(); // 가능
}
}
}9.5.2 바깥클래스의 객체접근
중첩클래스 내부에서 this는 해당 중첩 클래스의 객체를 말한다.
만약 중첩클래스 내부에서 바깥 클래스 객체를 얻으려면 바깥클래스이름에 this 를 붙여주면된다.
바깥클래스이름.this -> 바깥객체
package ch09.sec05.exam02;
public class A {
//A의 인스턴스 필드
String field = "A-field";
//A의 인스턴스 메소드
void method() {
System.out.println("A-method");
}
//인스턴스 멤버 클래스
class B{
//B 인스턴스 필드
String field = "B-field";
//B 인스턴스 메소드
void method() {
System.out.println("B-method");
}
//B인스턴스 메소드
void print() {
//B객체의 필드와 메소드 사용
System.out.println(this.field);
this.method();
//A객체의 필드와 메소드 사용
System.out.println(A.this.field);
A.this.method();
}
}
//A의 인스턴스 메소드
void useB() {
B b = new B();
b.print();
}
}package ch09.sec05.exam02;
public class AExample {
public static void main(String[] args) {
// A객체생성
A a = new A();
//A 메소드 호출
a.useB();
}
} 
9.6 중첩 인터페이스
중첩 인터페이스는 클래스의 멤버로 선언된 인터페이스를 말한다.
인터페이스를 클래스 내부 선언하는 이유는 해당클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해서다.
class A{
[public|private] [static] interface B{
//상수필드 추상메소드 디폴트메소드 정적메소드
}외부의 접근을 막지 않으려면 public을 붙이고 a클래스 내부에서만 사용하려면 private를 붙인다.
접근 제한자를 붙이지 않으면 같은 패키지 안에서만 접근이 가능하다.
그리고 a객체 없이 b인터페이스를 사용할 수 잇도록 하기 위해 static을 추가할 수 잇다.
중첩인터페이스는 안드로이드와 같은 ui 프로그램에서 이벤트를 처리할 으로 많이 활용된다.
예를들어 버튼을 클릭햇을때 이벤트를 처리할 중첩 인터페이스를 구현해서 만든다.
외부에서 접근이 간으하도록 public 이면서 Button객체 없이 사용할수있는 static 중첩인터페이스로
ClickListener를 선언하였다. 그리고 추상메소드인 onClick()을 선언했다.
onClick메소드는 버튼이 클릭되엇을때 호츨될 메소드이다.
Button 클래스에 ClkickListner 타입의 필드와 setter를 추가해서 외부에서 setter를 통해
ClkickListner 구현 객체를 필드에 저장할수있도록 했다.
버튼이 클릵되엇을때 실행할 메소드로 click ()를 다음과 같이 추가한다. 실행내용은 clickListener 인터페이스
버튼을 이용해서 onClick()추상메소드를 호출한다.
package ch09.sec06.exam03;
public class Button {
//정적멤버 인터페이스
public static interface ClickListener{
void onClick();
}
//필드
private ClickListener clickListener;
//메소드
public void setClickLisntener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public void click() {
this.clickListener.onClick();
}
}package ch09.sec06.exam03;
public class ButtonExample {
public static void main(String[] args) {
// ClickListener필드는 setter를 통해 제공된 ClickLisnter 구현 객체의 참조를 갖고잇다.
// 따라서 onClick()메소드를 호출하면 ClickListenerrngus 구현 객체의 onClick()메소드가 실행된다.
//Ok버튼 객체 생성
Button btnOk = new Button();
//Ok버튼 클릭 이벤트를 처리할 ClickListner 구현 클래스(로컬 클래스)
class OkListener implements Button.ClickListener //Button클래스 안의 인터페이스 참조
{
@Override
public void onClick() {
System.out.println("Ok 버튼을 클릭했습니다.");
}
}
//Ok 버튼 객체에 ClickLisnter구현객체 주입
btnOk.setClickLisntener(new OkListener());
//Ok버튼 클릭하기
btnOk.click();
//-----------------------------
//Cancel 버튼객체 생성
Button btnCancel = new Button();
//Cancel 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬클래스)
class CancelListener implements Button.ClickListener{
@Override
public void onClick() {
System.out.println("Cancel 버튼을 클릭했습니다.");
}
}
//Cancel 버튼 객체에 ClickListener 구현 객체 주입
btnCancel.setClickLisntener(new CancelListener());
//Cancel 버튼 클릭하기
btnCancel.click();
}
}OkListener와 CancelListener은 버튼 이벤트를 처리할 ClickListner 구현클래스로
onClick()메소드를 재정의해서 버튼이 클릭되엇을때 해야할일을 코딩한다.
btnOk와 btnCancel은 클릭처리를 담당할 ClickListner 구현객체를 설정하는 코드다.
실제 click()메소드를 호출하면 버튼에 설정된 ClickListner 구현객체의 메소드가 실행된다.
버튼에 어떤 ClickListner 구현객체가 설정되엇느냐에 따라 실행결과가 달라진다.(다형성)
2022.11.23 리뷰
11.2111.22 양일동안 국비학원을 알아보느라 진도를 나가지 못했다.2월쯤에 시작할 것 같다.
상담 및 면접을 보고 왔으며 1월
후회없는 시간을 보내지 않기 위해 많은 노력을 하고자 한다.
물론 기초부터 알려주는 곳이지만 진도가 빠르기에 어려움이 있을 수 있다.
천천히 나아가고 싶은 마음도 있다.
오랜만에 중요한 것은 꺾이지 않는 마음이라는 것을 마음에 새기고 나아가자 한다.
화이팅..! 어디서 유입되는지는 모르겠지만 댓글 달아주셔서 감사합니다~!
'기초단계 > JAVA' 카테고리의 다른 글
| 2022.11.25-1 JAVA 예외 처리 (1) | 2022.11.25 |
|---|---|
| 2022.11.24-1 JAVA 라이브러리와 모듈 (0) | 2022.11.25 |
| 2022.11.20-2 JAVA 인터페이스 2 (0) | 2022.11.20 |
| 2022.11.20-1 JAVA 인터페이스 1 (2) | 2022.11.20 |
| 2022.11.19-2 JAVA 상속 2 (0) | 2022.11.20 |