본문 바로가기
카테고리 없음

[JAVA 기초] 자바 중첩 클래스 (inner class) / 내부클래스, 외부클래스 익명클래스

by dev수니 2021. 4. 10.
반응형

 

 

 1  중첩 클래스의 정의

 

 

하나의 클래스 내부에 또 다른 클래스가 내포되어 있는 상태이다. 

 

자바 4대 중첩 클래스로 중첩클래스(inner class) 스태틱 중첩 클래스(static inner class) , 로컬 중첩 클래스 (local inner class) , 익명 중첩 클래스 (anonymous inner class) 로 나뉜다.

 

 

 

 

중첩클래스를 사용하는 방법은 다음과 같다.

 

 

 


 

 

 2  중첩 클래스(Inner class)

 

중첩 클래스는 외부클래스가 내부클래스를 감싸고 있는 형태이다. 이 클래스의 특징은 외부클래스가 내부클래스의 멤버를 사용하지 못한다는 것이다. 만약 내부클래스 멤버를 사용하고 싶을 경우 내부클래스의 객체를 발생시키면 사용할 수 있다. 또한 일반 내부클래스 안에서는 static 멤버를 선언할 수 없다.

 

다음은 inner class 의 예제이다. 객체 생성부분을 유의깊게 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package innerClass;
 
class Outer{
    private int num = 5;
    
    class Inner{
        int getNum() {
            return num;        // Outer의 변수를 리턴
        }
    }
}
public class InnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();        // Outer 객체 생성
        Outer.Inner inner = outer.new Inner();    // Outer 객체 내의 Inner 객체 생성
        System.out.println("private num : " + inner.getNum());    // inner. 으로 접근가능
    }
}
cs
private num : 5

 

Outer 객체에 num 변수를 private 형태로 넣어주었고 Inner 클래스에서 num 변수에 접근하는 메서드를 만들어주었다. 

Outer 객체를 생성하고 Outer 객체 내의 Inner 객체 생성를 생성해주어 Inner 객체에서 getNum() 메서드를 이용해 num 값에 접근했을 때 정상적으로 출력되는 모습이다.

 

객체를 생성할 때는 다음과 같이 생성한다.

 

외부클래스 객체1 = new 외부클래스();
외부클래스.내부클래스 객체2 = 객체1.new 내부클래스(); 

 

 

 

 

 

 

 

 

 

 

 3  정적 중첩 클래스(Static inner class)

 

정적 중첩 클래스는 중첩 클래스 중에서 static을 사용할 수 있는 클래스이다. static 클래스의 특성상 내부에 static 멤버를 만들 수 있다. 다음 예제에서 객체 생성부분을 유의깊게 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package innerClass;
 
class Outer2 {
    static class Static2 {
        void m() {
            System.out.println("스태틱 클래스의 m() 메서드.");
        }
    }
}
public class InnerClass_Static {
    public static void main(String[] args) {
        Outer2.Static2 obj = new Outer2.Static2();
        obj.m();
    }
}
cs
스태틱 클래스의 m() 메서드.

 

위과 같이 Static2 객체를 생성하려면 다음과 같이 작성한다.

 

  외부클래스.내부클래스 변수명 = new 외부클래스.내부클래스();

 

위의 static 이 없는 중첩클래스와는 다르게 객체를 생성한다. 위와 같이 객체를 생성할 경우 에러가 발생한다. 

 

 

 

 

 

 

 

 

 

 4  지역 중첩 클래스 (Local inner class)

 

다음은 지역 중첩 클래스의 예제이다. 외부클래스의 메서드 내에 내부 클래스가 존재한다. 메서드 내에 존재하기 때문에 외부에서 객체를 생성할 수 없다. 따라서 객체를 생성할 때에는 내부클래스가 위치한 메서드 내에서만 객체를 생성시킬 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package innerClass;
 
class Outer3{
    private int num = 55;
    void m3() {
        class Local3{    // 메서드 안에 내부클래스 생성 : 지역중첩클래스
            void showNum() {    // 내부클래스의 메서드
                System.out.println("private num : "+ num);    // num값을 출력
            }
        }
        Local3 obj1 = new Local3();    // showNum() 접근하기 위해 내부클래스의 객체 생성
        obj1.showNum();        // 지역중첩클래스의 showNum() 
    }
}
public class InnerClass_Local {
    public static void main(String[] args) {
        Outer3 obj2 = new Outer3();    // 외부클래스 생성
        obj2.m3();        // m3()를 호출하면 내부클래스 객체의 showNum()이 호출
    }
}
cs
private num : 55

 

위와 같이 외부클래스 내의 메서드 내부에 내부클래스를 생성해주었다. 그리고 외부클래스에서 선언함 private형태의 변수 num을 출력하는 메서드 showNum() 을 내부클래스 안에 선언해주었다. 이 메서드를 호출하기 위해서 내부클래스가 위치한 외부클래스의 메서드 m3()에서 내부클래스의 객체를 생성해주었고 그 객체의 멤버인 showNum() 을 호출하였다. 

 

외부에서는 지역 중첩 클래스에 접근할 수 없기 때문이다. 그리고 main에서 외부클래스의 객체를 생성해주고 m3() 를 호출하면 m3() 내부에 내부클래스의 객체를 생성시켜 놓았고 또 그의 메서드도 접근시켜놨기 때문에 줄8이 실행될 수 있다.

 

 

 

 

 

 

 

 5  익명 중첩 클래스 (Anonymous inner class)

 

위 지역 중첩 클래스의 변형된 형태이다. 익명의 형태이기 때문에 객체 생성과 동시에 부모클래스를 상속받아 내부에서 오버라이딩해서 사용한다.

 

내부클래스를 먼저 선언하고난 다음 외부클래스를 선언하고 그 내부의 메서드 안에 내부클래스를 new 해서 오버라이딩된 내용들을 선언하여 사용한다.

 

다음 예제를 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package innerClass;
 
interface AAAA {    // 익명클래스
    public String food = "";
    public String action = "";
    public static void getAction(){
    }
}
public class Innerclass_AnoNew {    // 외부클래스
    public static void main(String[] args) { //외부클래스 내의 메서드 main()
        new AAAA() {        // 익명클래스의 객체 생성==내부클래스
            String food = "햄버거";    
            String action = "먹는다.";
            public void getAction(){    // 외부클래스 내에서 오버라이딩해주었다.
                System.out.println(food + action);
            }
        };    // 객체의 선언과 동시에 오버라이딩했기 때문에 ;표시
        AAAA.getAction();
    }
}
cs
햄버거먹는다.

 

위와 같이 인터페이스에 변수 food와 action, 메서드 getAction()을 선언해주었다. 

 

그리고 외부클래스 Innerclass_AnoNew 의 메서드 main()에 new AAA로 내부에 익명의 객체를 생성하고 생성과 동시에 변수의 값을 설정하고 메서드 오버라이딩해주었다. 생성해준 객체는 내부클래스가 된다.

 

따라서 줄17에서 부모클래스인 인터페이스의 메서드 getAction()을 호출 한 결과 외부클래스의 내부에서 정의해준 값이 출력되었다. 

 

혹시 내부클래스(인터페이스 객체)로 getAction을 호출하는 방법은 없을까?

 

그래서 줄10의 AAAA 인터페이스의 객체를 생성할 때 AAAA aa = new AAAA() { 로 변경하고 줄6의 getAction 메서드의  static을 빼고 줄17에서 aa.getAction();으로 고치면 된다. 코드는 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package innerClass;
 
interface AAAA {
    public String food = "";
    public String action = "";
    public void getAction();
}
public class Innerclass_AnoNew {
    public static void main(String[] args) {
        AAAA aa = new AAAA() {
            String food = "햄버거";
            String action = "먹는다.";
            public void getAction(){
                System.out.println(food + action);
            }
        };
        aa.getAction();
    }
}
cs

 

 

 

 

 

반응형

댓글