본문 바로가기
Back-end/Java_T.I.L

[TIL 220111] 자바의정석 7. 객체지향 프로그래밍 II (3)

by 사장님나빠여 2022. 1. 12.

6. 추상클래스(abstract class)

6.1 추상클래스란?

추상클래스란, 멤버에 관계없이 미완성 메서드(추상메서드)를 포함하고 있다는 의미다. 추상클래스 자체로는 클래스로서의 역할을 다 못하지만. 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상클래스로서 중요한 의미를 갖는다. 추상클래스는 'abstract'를 붙이기만 하면 된다. 이렇게 함으로써 이 클래스를 사용할 때, 클래스의 선언부의 abstract를 보고 이 클래스에는 추상메서드가 있으니 상속을 통해 구현해주어야 한다는 것을 쉽게 알 수 있을 것이다.

추상클래스는 추상메서드를 포함하고 있다는 것을 제외하고 일반클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.

 

6.2 추상메서드(abstract method)

선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다. 메서드를 미완성 상태로 남겨 놓은 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상 클래스는 선언부만을 작성하고, 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워 두는 것이다. 그래서 추상클래스를 상속받는 자손 클래스는 조상의 추상 메서드를 상호아에 맞게 적절히 구현해주어야 한다.

abstract class Plaer{
	//abstract 리턴타입 메서드이름();
    abstract void play(int pos);
    abstract void stop();
}
class AudioPlayer extends Player{
	void play(int pos){ /* 내용생략 */ }
	void stop(){ /* 내용생략 */ }
}

추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다. 만일 조상으로부터 상속받은 추상메서드 중 하나라도 구현하지 않는다면, 자손클래스 역시 추상클래스로 지정해 주어야 한다.

 

 

6.3 추상클래스의 작성

상속이 자손 클래스를 만드는데 조상 클래스를 사용하는 것이라면, 이와 반대로 추상화는 기존의 클래스의 공통부분을 뽑아내서 조상 클래스를 만드는 것이라고 할 수 있다. 추상화를 구체화와 반대되는 의미로 이해하면 보다 쉽게 이해할 수 있다. 상속계층도를 따라 내려갈수록 클래스는 점점 기능이 추가되어 구체화의 정도가 심해지며, 상속계층도를 따라 올라갈수록 클래스는 추상화 정도가 심해진다고 할 수 있다. 상속계층도를 따라 내려갈수록 세분화되며, 올라갈수록 공통요소만 남게된다.

더보기

추상화 : 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업

구체화 : 상속을 통해 클래스를 구현, 확장하는 작업

각 클래스의 공통부분을 뽑아내서 Unit클래스를 정의하고 이로부터 상속받도록 하였다. 이 Unit클래스는 다른 유닛을 위한 클래스를 작성하는데 재활용될 수 있을 것이다. 


7. 인터페이스(interface)

7.1 인터페이스란?

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다. 

인터페이스도 추상클래스처럼 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움을 줄 목적으로 작성된다.

7.2 인터페이스의 작성

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 clas대싱 interface를 사용한다는 것만 다르다. 그래고 interface에도 클래스와 같이 접근제어자로 public 또는 default를 사용할 수 있다.

 

interface 인터페이스이름{
	public static final 타입 상수이름 = 값;
	public abstract 메서드이름(매개변수목록);
}
더보기

인터페이스 멤버들의 제약사향

-모든 멤버변수는 public static final이어야 하며, 이를 생략할 수 있다.

-모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.

    단, static메서드와 디폴트 메서드는 예외(JDK 1.8부터)

인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다. 원래는 인터페이스의 모든 메서드는 추상메서드이어야 하는데, JDK 1.8부터 인터페이스에 static메서드와 디폴트 메서드(default method)의 추가를 허용하는 방향으로 변경되었다. 

 

7.3 인터페이스의 상속

인터페이스는 인터페이스로부터만 상속을 받을 수 있으며, 클래스와는 달리 다중상속, 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.

interface Movagle{
	//지정된 위치(x, y)로 이동하는 기능의 메서드
    void move(int x, int y);
}
interfacce Attackable{
	//지정된 대상(u)를 공격하는 메서드
    void attack(Unit u);
}
interface Fightableextends Movablble, Attackable{}

클래스의 상속과 마찬가지로 자손 인터페이스(Fightable)는 조상 인터페이스(Movable, Attackable)에 정의된 멤버를 모두 상속받는다. 그래서 Fightable에 정의된 멤버가 하나도 없지만 조상 인터페이스로부터 상속받은 두 개의 추상메서드, move()와 attack()을 멤버로 갖는다.

7.4 인터페이스의 구현

인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 추상클래스가 상속을 통해 추상메서드를 완성하는 것처럼, 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 하는데, 그 방법은 추상클래스가 자신을 상속받는 클래스를 정의하는 것과 다르지 않다. 다만 클래스는 확장한다는 의미의 키워드 'extends'(인터페이스끼리 구현받을 때도)를 사용하지만 인터페이스를 구현한다는 의미의 키워드 'implements'를 사용할 뿐이다. 그리고 인터페이스는 상속과 구현을 동시에 할 수도 있다. 만일 구현하는 인터페이스 메서드 중 일부만 구현한다면, abstract를 붙여서 추상클래스로 선언해야 한다. 

예제 7-24

예제에 사용된 클래스와 인터페이스간의 관계를 그려보면 다음과 같다.

실제로 Figter클래스는 Unit클래스로부터 상속받고 Fightable인터페이스만을 구현했지만, Unit클래스는 Object의 자손이고, Fightable인터페이스는Attackable과 Moveable인터페이스의 자손이므로 Fighter클래스는 이 모든 클래스와 인터페이스의 자손이 되는 셈이다.

오버라이딩 할 때는 조상의 메서드보다 넓은 범위의 접근 제어자를 지정해야 한다. Movable 인터페이스의 'void move(int x, int y)'와 같이 정의되어 있지만 사실 'public abstract'가 생략된 것이 기 때문에 실제로 'public abstract void move(int x, int y)'이다. 그래서 이를 구현하는 Fighter클래스에서는 'void move(int x, int y)'의 접근제어자를 반드시 public으로 해야하는 것이다.

 

7.5 인터페이스를 이용한 다중상속

두 조상으로부터 상속받는 멤버 중에서 멤버변수의 이름이 같거나 메서드의 선언부가 일치하고 구현 내용이 다르다면 이 두 조상으루보터 상속받는 자손클래스는 어느 조상의 것을 상속받게 되는 것인지 알 수 없다.  그래서 다중상속은 장점도 있지만 단점이 더 크다고 판단하였기 때문에 자바에서는 다중상속을 허용하지 않는다. 다른 객체지향 언어인 C++에서는 다중상속을 허용하기 때문에 자바는 다중상속을 허용하지 않는다는것이 단점으로 부각되는 것에 대한 대응으로 '자바로 인터페이스를 이용하면 다중상속이 가능하다'라고 하는 것일 뿐 자바에서 인터페이스로 다중상속을 구현하는 경우는 거의 없다.

 

인터페이스는 static상수만 정의할 수 있으므로 조상클래스의 멤버변수와 충돌하는 경우는 거의 없고 충돌된다 하더라도 클래스 이름을 붙여서 구분이 가능하다. 그리고 추상메서드는 구현 내용이 전혀 없으므로 조상클래스의 메서드와 선언부가 일치하는 경우에는 당연히 조상 클래스 쪽의 메서드를 상속받으면 되므로 문제되지 않는다. 이렇게 하면 상속받는 멤버의 충돌을 피할 수는 있지만 다중상속의 장점을 잃게 된다. 만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면, 두 조상클래스 중에서 비중이 높은 쪽을 선택하고 다른 한쪽은 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 어느 한쪽의 필요한 부분을 뽑아서 인터페이스로 만든 다음 구현하도록한다.

7.6 인터페이스를 이용한 다형성

인터페이스 역시 구현한 클래스의 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다. (1)인터페이스 Fightable을 클래스 Fighter가 구현했을 때, 다음과 같이 참조하는 것이 가능하다. (2)따라서 인터페이스는 다음과 같이 메서드의 매개변수의 타입으로 사용될 수 있다.

더보기

(1) Fightable f = (Fightable) new Fighter();  /  Fightable f = new Fighter(); 

 

(2) void attack(Fightable f) {    . . .    }

인터페이스 타입의 매개변수가 갖는 의미는 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 한다는 것이다. 그래서 attack 메서드를 호출할 때는 매개변수로 Fightable인터페이스를 구현한 클래스의 인스턴스를 넘겨주어야 한다. 리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다. 

Parseable인터페이슨느 구문분석(parsing)을 수행하는 기능을 구현할 목적으로 추상메서드 'parse(String fileName)'을 정의했다. 그리고 XMLParser클래스와 HTMLParser클래스는 Parseable 인터페이스를 구현하였다.

ParserManager클래스의 getParser메서드는 매개변수로 넘겨받는 type의 값에 따라 XMLParser인스턴스 또는 HTMLParser인스턴스를 반환한다.

getParser메서드의 수행결과로 참조변수 parser는 XMLParser인스턴스의 주소값을 갖게 된다. 마치 'Parseable parser = new XMLParser();'이 수행된 것과 같다.

 

7.7 인터페이스의 장점

더보기

인터페이스를 사용하는 이유와 장점

-개발시간을 단축시킬 수 있다.

-표준화가 가능하다.

-서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.

-독립적인 프로그래밍이 가능하다

1. 개발시간을 단축시킬 수 있다.

인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문이고 동시에 다른 한쪽에서는 인터페이스를 구현하는 클래스를 작성하게 되면, 인터페이스를 구현하는 클레스가 작성될 때 까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.

 

2.표준화가 가능하다.

프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 갭라이 가능하다.

 

3. 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.

서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어줄 수 있다

 

4. 독립적인 프로그래밍이 가능하다.

인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 떄문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능하다. 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해서 간적접인 관계로 변경하면, 한 클래스의 변경이 관련된

다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.

 

7.8 인터페이스의 이해

더보기

-클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.

-메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언부만 알면 된다.(내용 몰라도 된다)

위 코드의 경우 클래스 A를 작성하려면 클래스B가 이미 작성되어 있어야 한다. 그래고 클래스 B의 methodB()의 선언부가변경되면, 이를 사용하는 클래스 A도 변경되어야 한다. 이와 같이 직접적인 관계의 두 클래스는 한 쪽(Provider)이 변경되면 다른 한 쪽(User)도 변경되어야 한다는 단점이 있다. 

그러나 클래스 A가 클래스 B를 직접 호출하지 않고 인터페이스를 매개체로 해서 클래스 A가 인터페이스를 ㅌ오해서 클래스 B의 메서드에 접근하도록 하면, 클래스 B에변경사항이 생기거나 클래스 B와 같은 기능의 다른 클래스로 대체 되어도 클래스 A는 전혀 영향을 받지 않도록 하는 것이 가능하다. 두 클래스간의 관계를 변경하기 위해서는 먼저 인터페이스를 이용해서 클래스 B(Provider)의 서언과 구현을 분리해야 한다.

class B implement I{
	public void method B(){
    	System.out.println("methodB in B class");
    }
}

class A{
	public void methodA(I i){
    	i.methodB();
    }
}

클래스 B에 정의된 메서드를 추상메서드로 정의하는 인터페이스 I를 정의하고 클래스 B가 인터페이스 I를 구현하도록 한다. 그러면 클래스 A는 위처럼 클래스 B대신 인터페이스 I를 사용해서 작성할 수 있다.

 

클래스 A를 작성하는데 있어서 클래스 B가 사용되지 않았다는 점에 주모갛면 이제 클래스 A와 클래스 B는 'A-B'의 직접적인 관계에서 'A-I-B'의 간접적인 관계로 바뀐다. 결국 클래스 A는 여전히 클래스 B의 메서드를 호출하지만, 클래스 A는 인터페이스 I하고만 직접적인 관계에 있기 때문에 클래스 B의 변경에 영향을 받지 않는다. 클래스 A는 인터페이스를 통해 실제로 사용하는 클래스의 이름을 모라도 되고 심지어는 실제로 구현된 클래스가 존재하지 않아도 문제되지 않는다. 클래스 A는 오직 직접적인 관계에 있는 인터페이스 I의 영향만 받는다.

 

7.9 디폴트메서드와 static메서드

원래는 인터페이스에 추상 메서드만 선언할 수 있는데 JDK1.8부터 디폴트 메서드와 static메서드도 추가할 수 있게 되었다. static메서드는 인스턴스와 관계가 없는 독립적인 메서드이기 때문에 예전부터 인터페이스에 추가하지 못할 이유가 없었다. 그러나 자바를 보다 쉽게 배울 수 있도록 규칙을 단순히 할 필요가 있어서 인터페이스의 모든 메서드는 추상 메서드이어야 한다는 규칙에 예외를 두지 않았다. 

 

가장 대표적인 예로 java.util.Collection 인터페이스가 있는데, 이 인터페이스와 관련된 static메서드들이 인터페이스에는 추상메서드만 선언할 수 있다는 원칙 때문에 별도의 클래스, Collections라는 클래스에 들어가게 되었다. 만일 인터페이스에 static메서드를 추가할 수 있었다면, Collections클래스는 존재하지 않았을 것이다. 그리고 인터페이스의 static메서드 역시 접근 제어자가 항상 public이며, 생략할 수 있다.

 

디폴트 메서드

조상 크랠스에 새로운 메서드를 추가하는 것은 별 일이 아니지만, 인터페이스의 경우에는 보통 큰 일이 아니다. 인터페이스에 메서드를 추가한다는 것은, 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 하기 때문이다. 

인터페이스가 변경되지 않으면 좋겠지만, 아무리 설계를 잘해도 언젠가 변경은 발생하기 마련이다. JDK설계자들은 고심 끝에 디폴트 메서드(default method)라는 것을 고안해 내었다. 디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다. 디폴트 메서드 앞에 키워드 default를 붙이며, 추상 메서드와 달리 일반 메서드처럼 몸통{ }이 있어야 한다. 디폴트 메서드 역시 접근 제어자가 public이며, 생략 가능하다.

더보기

디폴트 메서드의 이름 중복되어 생기는 충돌을 해결하는 규칙

 

1. 여러 인터페이스의 디폴트 메서드 간의 충돌

  -인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.

2. 디폴트 메서드와 조상 클래스 메서드 간의 충돌

  -조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

 

 


8. 내부클래스(inner class)

8.1 내부 클래스란?

내부클래스는 클래스 내에 선언된 클래스이다. 클래스에 다른 클래스를 선언하는 이유는 두 클래스가 서로 긴밀한 관계에 있기 때문이다. 한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다는 장점을 얻을 수 있다.

더보기

내부 클래스의 장점

  -내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.

  -코드의 복잡성을 줄일 수 있다(캡슐화)

8.2 내부 클래스의 종류와 특징

내부 클래스 특   징
인스턴스 클래스
(instance class)
외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언된다.
스태틱 클래스
(static class)
외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static멤버처럼 다루어진다. 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다.
지역 클래스
(local class)
외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
익명 클래스
(anonymous class)
클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)

 

8.3 내부 클래스의 선언

아래의 코드에는 외부 클래스 (Outer)에 3개의 서로 다른 종류의 내부 클래스를 선언했다. 양쪽의 코드를 비교해 보면 내부 클래스의 선언위치가 변수의 선언위치와 동일함을 알 수 있다. 변수가 선언된 위치에 따라 인스턴스 변수, 클래스 변수(static변수), 지역변수로 나뉘듯이 내부 클래스도 이와 마찬가지로 선언된 위치에 따라 나뉜다. 긜고 각 내부 클래스의 선언 위치에 따라 같은 선언위치의 변수와 동일한 유효범위(scope)와 접근성(accessibility)을 갖는다.

 

8.4 내부 클래스의 제어자와 접근성

위 8.3에 나온 코드에서 인스턴스 클래스(InstanceInner)와 스태틱 클래스(StaticInner)는 외부 클래스(Outer)의 멤버변수(인스턴스변수와 클래스변수)와 같은 위치에 선언되며, 또한 멤버변수와 같은 성질을 갖는다. 따라서 내부 클래스가 외부 클래스의 멤버와 같이 간주도고, 인스턴스 멤버와 static멤버 간의 규칙이 내부 클래스에도 똑같이 적용된다.

 

내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있을 뿐만 아니라, 멤버변수들처럼 private, protected과 같은 접근제어자도 사용이 가능하다. 내부클래스 중에서 스태틱 클래스(StaticInner)만 static멤버를 가질 수 있다. 드문 경우지만 내부 클래스에 static변수를 선언해야한다면 스태틱클래스로 선언해야 한다. 다만 final과 static이 동시에 붙은 변수는 상수(constant)이므로 모든 내부 클래스에서 정의가 가능하다.

 

인스턴스멤버는 같은 클래스에 있는 인스턴스 멤버와 static멤버 모두 직접 호출이 가능하지만, static멤버는 인스턴스멤버를 직접 호출할 수 없는 것처럼, 인스턴스클래스는 외부 클래스의 인스턴스 멤버를 객체생성 없이 바로 사용할 수 있지만, 스태틱 클래스는 외부 클래스의 인스턴스 멤버를 객체 없이 사용할 수 없다.

마찬가지로 인스턴스클래스는 스태틱 클래스의 멤버들을 객체생성 없이 사용할 수 있지만, 스태틱 클래스에서는 인스턴스클래스의 멤버들을 객체 생성 없이 사용할 수 없다.

예제 7-33

내부 클래스에서 외부 클래스의 변수들에 대한 접근성을 보여 주는 예제이다. 인스턴스클래스(InstanceInner)는 외부클래스(Inner)의 인스턴스멤버이기 때문에 인스턴스변수 outerlv와 static변수 outerCv를모두 사용할 수 있다. 심지어는 outerIv의 접근 제어자가 private일지라도 사용가능하다. 

스태틱클래스(StaticInner)는 외부 클래스(Inner)의 static멤버이기 때문에 외부 클래스의 인스턴스멤버인 outerIv와 InstanceInner를 사용할 수 없다. 단지 static멤버인 outerCv만을 사용할 수 있다.

지역클래스(LocalInner)는 외부 클래스의 인스턴스멤버와 static멤버를 모두 사용할 수 있으며, 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다. 단, final이 붙은 지역변수만 접근 가능한데 그 이유는 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문이다.

JDK1.8부터 지역 클래스에서 접근하는 지역 변수 앞에 final을 생략할 수 있게 바뀌었다. 대신 컴파일러가 자동으로 붙여준다. 편의상 final을 생략할 수 있게 한 것일 뿐 해당 변수의 값이 바뀌는 문장이 있으면 컴파일 에러가 발생한다.

예지 7-34

외부클래스가 아닌 다른 클래스에서 내부 클래스를 생성하고 내부 클래스의 멤버에 접근하는 예제이다.

실제로 이런 경우가 발생했다는 것은 내부 클래스로 선언해서는 안 되는 클래스를 내부 클래스로 선언했다는 의미이다.

컴파일시 생성되는 클래스 파일은 다음과 같다.

 

Inner.class

Outer.class

Outer$InstanceInner.class

Outer$StaticInner.class

Outer$LocalInner.class 

 

컴파일 했을 때 생성되는 파일명은 '외부 클래스명$내부 클래스명.class' 형식으로 되어 있다. 다만 서로 다른 메서드 내에서는 같은 이름의 지역변수를 사용하는 것이 가능한 것 처럼, 지역 내부 클래스는 다른 메서드에 같은 이름의 내부 클래스가 존재할 수 있기 때문에 내부 클래스명 앞에 숫자가 붙는다.

 

내부 클래스와 외브 클래스에 서언된 변수의 이름이 같을 때 변수 앞에 'this' 또는 '외부 클래스명.this'를 붙여서 서로 구별할 수 있다는 것을 보여준다.

8.5 익명 클래스(anonymous class)

익명클래스는 특이하게도 다른 내부 클래스들과는 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.

new 조상클래스이름(){
	//멤버선언
}
new 구현인터페이스이름(){
	//멤버선언
}

이름이 없기 때문에 생성자도 가질 수 없으며, 조상클래스의 이름이나 구현하고자 하는 인터페이스의이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.

 

댓글