▶ 중첩 클래스 및 중첩 인터페이스를 사용하는 이유


- 자바는 객체 지향 프로그램으로 각 클래스가 관계를 맺으며 상호작용을 한다. 어떤 클래스는 많은 클래스와 상호작용을 하기도 하지만, 다른 어떤 클래스는 특정 클래스하고만 상호작용을 하기도 한다. 여러 클래스와 상호작용을 할 때는 해당 클래스를 독립적으로 생성하는 것이 좋지만, 특정 클래스하고만 상호작용을 할 경우 특정 클래스 내부에 해당 클래스를 생성하는 것이 효율적이다.


- 중첩 인터페이스는 해당 클래스와 깊은 상호작용을 하는 구현 클래스를 생성하기 위해 사용된다.




▶ 중첩 클래스(Nested Class)


- 하나의 클래스 내부에 선언된 다른 클래스를 의미한다. 즉, 포함되어지는 클래스이다.


- 두 클래스의 멤버간에 접근이 용이하다. 중첩 클래스는 자신을 포함하는 클래스의 모든 멤버에 접근할 수 있다. 즉, 접근 제한자가 private인 멤버라 할지라도 중첩 클래스는 접근할 수 있다.


- 불필요한 상호작용을 맺은 클래스들을 외부로부터 감춤으로써 코드가 간결해진다.



class ClassName {

class NestedClassName {

...

}

}





▶ 멤버 클래스


- 클래스의 멤버로서 선언되는 중첩 클래스


- 해당 클래스나 객체가 사용 중일 경우 재사용이 가능하다.


- 멤버 클래스도 하나의 클래스이기 때문에 컴파일하면 바이트 코드 파일(~.class)가 생성된다.


멤버 클래스의 바이트 코드 파일 이름 : 바깥클래스명$ 멤버클래스명.class

로컬 클래스의 경우 : 바깥클래스명$1 로컬클래스명.class


- 인스턴스 멤버 클래스


class A {

class B { ... } // A객체를 생성해야 B 중첩 클래스(인스턴스 멤버 클래스)를 사용할 수 있다.

}


  • 중첩 클래스를 포함한 클래스를 생성해야만 해당 중첩 클래스를 사용할 수 있다.
  • 정적 필드와 메소드는 선언할 수 없다.
  • 외부 클래스에서 인스턴스 멤버 클래스를 생성하려면 바깥 클래스를 먼저 선언(객체 생성)해야 한다.
- 정적 멤버 클래스


class A {

static class B { ... } // A 클래스로 바로 접근 가능한 B 중첩 클래스(정적 멤버 클래스)

}


  • 중첩 클래스를 포함한 클래스로 바로 접근 가능한 중첩 클래스
  • 모든 종류의 필드와 메소드를 선언할 수 있다.
  • 바깥 객체를 생성하지 않아도 바로 정적 멤버 클래스를 이용할 수 있다.



▶ 로컬 클래스

- 메소드 내부에서 선언된 중첩 클래스

- 메소드 실행 시에만 사용되며, 메소드가 종료되면 사라진다.

- 로컬 클래스는 접근 제한자(public, private, protected) 및 static을 붙일 수 없다. 메소드 내부에서 사용되므로 접근을 제한할 필요가 없기 때문이다.

- 정적 필드와 메소드를 선언할 수 없다.

- 로컬 클래스가 선언된 메소드는 new 연산자를 통해 객체를 생성해야 해당 로컬 클래스를 사용할 수 있다.

- 다음과 같이 비동기 처리를 위한 스레드 객체 생성 시 사용된다.

void method() {

class DownloadThread extends Thread { ... } //로컬 클래스

DownloadThread th = new DownloadThread(); // 선언과 초기화 필수

th.start();

}





▶ 중첩 클래스의 접근 제한


- 멤버 클래스

  • 인스턴스 멤버 클래스는 바깥 클래스의 인스턴스 필드를 통해 객체를 생성하거나 인스턴스 메소드 내부에서 객체를 생성할 수 있지만 정적 필드나 메소드는 해당되지 않는다. 즉, 바깥 클래스의 정적 멤버에 포함될 수 없다.
  • 인스턴스 멤버 클래스 내부에서 바깥 클래스로 접근할 때 모든 필드와 메소드가 가능하다. 즉, 바깥 클래스의 정적 멤버에 접근가능하다.
  • 정적 멤버 클래스는 바깥 클래스의 모든 필드의 초기값으로 혹은 모든 메소드에서 객체를 생성할 수 있다.
  • 정적 멤버 클래스 내부에서는 바깥 클래스의 정적 필드와 메소드에만 접근할 수 있다. 즉, 바깥 클래스의 인스턴스 멤버에 접근할 수 없다.

- 로컬 클래스
  • 로컬 클래스 내부에서는 바깥 클래스로 제한 없이 접근할 수 있다.
  • 로컬 클래스에서 사용되는 매개변수와 로컬 변수는 모두 final 특성(최종값)을 갖는다.
☞ 로컬 클래스의 객체는 메소드 실행이 끝나도 힙 메모리에 남아있으므로 사용할 수 있지만, 메소드의 매개변수 및 로컬변수는 메소드 실행이 끝나면 사라지므로 로컬 객체에서 사용할 경우 에러가 발생한다. 해결 방법으로 컴파일 시 로컬 클래스에서 사용하는 매개변수 및 로컬변수는 로컬 클래스 내부의 기억장소에 두고 사용한다. 그러나 값이 수정되면 복사해 둔 기억장소가 변경되므로 이 문제를 해결하고자 변수를 final로 선언하여 수정을 맞는다. 쉽게 말해, final 로 선언된 매개변수와 로컬변수만 로컬 클래스에서 사용가능하다. 자바 8부터는 final 키워드 없이 선언되어도 여전히 값을 수정할 수 없는 final 특성을 갖는다.

☞ final 키워드의 존재 여부의 차이점은 로컬 클래스의 복사 위치이다. final 키워드가 있을 경우 로컬 클래스를 포함한 메소드 내부에서 지역 변수로 복사된다. 없을 경우 로컬 클래스의 필드로 복사된다.


- 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 아래와 같이 선언해야한다.

바깥클래스명.this.필드명;

바깥클래스명.this.메소드명;




▶ 중첩 인터페이스(Nested Interface)


- 클래스의 멤버로 선언된 인터페이스


- 주로 UI(User Interface) 프로그래밍에서 이벤트를 처리할 때 사용된다. 즉 해당 이벤트를 처리하는 구현 클래스를 만드는 것이다.


class ClassName {

interface NestedInterfaceName {

...

}

}







 

 

무명 클래스(Anonymous class)

 

- 말그대로 몸체는 있으나 이름만 없는 클래스를 의미하며, 하나의 객체만 사용할 경우에 이용한다. , 한번만 사용가능하다.


클래스명 변수명 = new 클래스명 { 클래스 몸체 };

 

- 무명 클래스의 선언은 하나의 실행문이므로 끝에 세미콜론(;)이 무조건 붙는다.

 

- 클래스명에 올 수 있는 것은 상속받고자 하는 부모 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 적어주면 된다.

 

- 무명클래스는 클래스를 정의하면서 동시에 객체를 생성하게 된다.

 

- 코드의 양을 줄일 수 있다는 장점이 있으나 코드가 난해해진다.

 

 

 

익명 구현 객체

 

- 무명클래스를 통해 인터페이스를 구현하고자 하는 일회성의 구현 객체를 말한다.

 

- 대부분 UI(user interface) 프로그래밍에서 이벤트를 처리하거나 임시 작업 스레드를 만들기 위해 익명 구현 객체를 많이 이용한다.

 

- 형식 


인터페이스타입 변수명 = new 인터페이스타입() {


//인터페이스에 선언된 추상메소드의 실체 메소드 선언


}; 



- 추가적으로 필드와 메소드도 선언이 가능하지만, 익명 객체 안에서만 사용할 수 있고, 해당 변수로는 접근할 수는 없다.





 

 

 

인터페이스(Interface)

 

- 추상 메소드들로만 이루어진 형태로, 객체의 사용 방법을 정의한 새로운 타입이다.

 

- 상수 외에 필드를 선언할 수 없다.

 

- 자바에서 인터페이스란 객체와 객체 사이의 상호 작용이 이루어지는 인터페이스이다.

 

- 추상 메소드의 성질을 이용하면, 인터페이스는 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하느냐에 따라 실행 내용과 리턴값이 다를 수 있다.

 

- , 개발 코드를 수정하지 않고 사용하는 객체만 변경하여 메소드를 실행한다.

 

- 객체의 교환성을 높여주기 때문에 다형성을 구현하는 매우 중요한 역할을 한다.

 

상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한 클래스를 만든다는 점에서 개념적인 차이가 있다. 그러나 둘 다 다형성을 구현하는 기술이다.


- 인터페이스를 구현하는 객체를 구현 객체라고 부르며, 구현 객체를 생성하는 클래스를 구현 클래스라고 부른다. 구현 클래스는 추상 메소드의 몸체를 반드시 구현하여야 한다.

 

- 인터페이스의 모든 메소드는 기본적으로 public 접근 제한자를 갖기 때문에 구현 클래스에서 작성할 때 public 보다 더 강한 접근 제한자(default, private )를 사용할 수 없다. , public을 생략해선 안된다.

 

- 상속과는 달리 구현 클래스는 다수의 인터페이스를 구현할 수 있다.

 

- 인터페이스끼리는 상속이 가능하다.

public interface 인터페이스1 extends 인터페이스2 { ... }

 

- 구현 클래스는 선언부에 implements 키워드를 추가하고 인터페이스 명을 명시해야 한다.

* implements 시행하다, 도구라는 뜻이다.

 

- 인터페이스 타입의 변수는 참조형 변수이기 때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장한다.


 


인터페이스의 구성 멤버

 

- 상수 필드 : 상수는 인터페이스에 고정된 값이므로 런타임 시에 데이터를 바꿀 수 없다. 상수를 선언할 때에는 반드시 초기값을 대입해야 한다.


public static final 자료형 변수명;


 

- 추상 메소드 : 객체가 사용할 메소드의 형태를 설명한 것으로, 어ᄄᅠᆫ 매개값이 필요하고 리턴 타입이 무엇인지만 알려준다. 실체 실행부는 해당 인터페이스를 구현하는 클래스에서 작성해야 한다.

 

- 디폴트 메소드 : 자바 8버전에서만 허용하는 멤버이며, 기존 인터페이스를 확장해서 사용하기 위함이다. 선언할 때 인터페이스를 구현한 실제 객체가 가지고 있는 메소드라고 생각하면 된다. 따라서 구현 객체에서는 인터페이스의 디폴트 메소드의 실체 메소드를 작성할 필요가 없다.

 

- 정적 메소드 : 자바 8버전에서만 허용하는 멤버이며, 디폴트 메소드와 달리 객체가 없어도 인터페이스만으로 호출이 가능하다. 쉽게 말해, 인터페이스를 선언하지 않고 "인터페이스이름.정적메소드명()"과 같이 바로 호출이 가능함.

 

 

 

인터페이스의 일반적인 형태

 

- 인터페이스의 모든 메소드는 추상 메소드로 간주되므로 abstract키워드는 사용하지 않는다.

 


public interface 인터페이스명 {

//상수

...

 

//추상 메소드

리턴타입 추상메소드1(...);

리턴타입 추상메소드2(...);

...


//디폴트 메소드 -> default를 붙여야한다. 안 붙이면 추상 메소드로 간주됨

default 리턴타입 메소드명(...) { ... }

...


//정적 메소드

static 리턴타입 메소드명(...) { ... }

}




public class 클래스명 implements 인터페이스명 {

 

//FIELDS

...

 

//CONSTRUCTOR

...

 

//METHODS

@Override

리턴타입 추상메소드1(...) {

    ...

}


@Override

리턴타입 추상메소드2(...) {

    ...

}

 

} 


- @Override 란 인터페이스의 추상 메소드에 대한 정확한 실체 메소드인지 컴파일러가 체크하도록 지시하는 어노테이션이다. 생략해도 상관없으나, 실체 메소드가 잘못되지 않도록 해주기 때문에 붙여 주는 것이 좋다.




▶ 인터페이스의 타입 변환


- 구현 객체가 인터페이스 타입으로 변환되는 것은 자동 타입 변환에 해당한다. 이렇게 자동 타입 변환된 구현 객체는 해당 클래스의 필드와 메소드를 사용할 수 없다. 즉, 인터페이스의 상수와 메소드만 사용가능하다.


- 반대로, 인터페이스 타입인 구현 객체를 강제 타입 변환하여 구현 클래스 타입으로 사용할 수 있다.


- 필드와 매개변수의 타입을 인터페이스로 선언하면 여러 구현 객체를 대입하여 다양한 실행 결과를 만들 수 있다.


+ Recent posts