'자바의 정석 3rd Edition'을 공부하며 정리한 내용입니다.
6. 추상클래스(abstract class)
6.1 추상클래스란?
- 추상클래스는 미완성 설계도
- 클래스가 미완성이라는 것은 멤버의 개수에 관계된 것이 아니라, 단지 미완성 메서드(추상 메서드)를 포함하고 있다는 의미
- 추상클래스로는 인스턴스를 생성할 수 없으며, 추상클래스는 상속을 통해 자손클래스에 의해서만 완성될 수 있음
- 추상클래스는 새로운 클래스를 작성하는데 있어 바탕이 되는 조상클래스로서 중요한 의미를 가짐
abstract class 클래스이름 {
...
}
- 추상클래스는 키워드
abstract
를 붙이면 됨
- 이 클래스를 사용할 때, 클래스 선언부의
abstract
를 보고 이 클래스에는 추상메서드가 있으니 상속을 통해 구현해주어야 한다는 것을 쉽게 알 수 있음
- 추상클래스는 추상메서드를 포함하고 있다는 것을 제외하고는 일반 클래스와 전혀 다르지 않음
- 추상클래스에도 생성자가 있으며, 멤버변수와 메서드를 가질 수 있음
6.2 추상메서드(abstract method)
- 추상메서드: 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것
- 추상메서드 사용 이유
- 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상 클래서에서는 선언부만 작성하고, 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워 두는 것
- 추상클래스를 상속받는 자손 클래스는 조상의 추상 메서드를 상황에 맞게 적절히 구현해주어야 함
abstract 리턴타입 메서드이름();
abstract
를 앞에 붙여주고, {} 대신 문장의 끝을 알리는 ';'을 적어줌
- 추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상 메서드를 모두 구현해주어야 함
- 만일 조상으로부터 상속받은 추상메서드 중 하나라도 구현하지 않는다면, 자손클래스 역시 추상클래스로 지정해 주어야 함
6.3 추상클래스의 작성
- 여러 클래스에 공통적으로 사용될 수 있는 클래스를 바로 작성하기도 하고, 기존의 클래스의 공통적인 부분을 뽑아서 추상클래스로 만들어 상속하는 경우도 있음
- 상속이 자손 클래스를 만드는데 조상 클래스를 사용하는 것이라면, 반대로 추상화는 기존의 클래스의 공통부분을 뽑아내서 조상 클래스를 만드는 것
- 상속계층도를 따라 내려올수록 클래스는 점점 기능이 추가되어 구체화의 정도가 심해지며, 상속계층도를 따라 올라갈수록 클래스는 추상화의 정도가 심해진다고 할 수 있음
- 상속계층도를 따라 내려 갈수록 세분화되며, 올라갈수록 공통요소만 남게 됨
추상화 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업
구체화 상속을 통해 클래스를 구현, 확장하는 작업
추상메서드로 하는 대신 아무 내용이 없는 일반 메서드({})로 작성할 수 있는데 추상메서드로 선언하는 이유
- 자손 클래스에서 추상메서드를 반드시 구현하도록 강요하기 위해서
- 추상메서드로 정의되어 있지 않고 빈 몸통만 가지도록 정의되어 있다면, 상속받는 자손 클래스에서는 이 메서드들이 온전히 구현된 것으로 인식하고 오버라이딩을 통해 자신의 클래스에 맞도록 구현하지 않을 수 있음
- abstract를 사용해 추상메서드로 정의해놓으면, 자손 클래스를 작성할 때 내용을 구현해주어야 한다는 사실을 인식하고 자신의 클래스에 알맞게 구현할 것
7. 인터페이스(interface)
7.1 인터페이스란?
- 인터페이스: 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없음
- 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않음
- 추상클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면, 인터페이스는 구현된 것은 아무 것도 없고 밑그림만 그려져 있는 '기본 설계도'라고 할 수 있음
7.2 인터페이스의 작성
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
- interface에는 접근제어자로 public 또는 default만 사용 가능
인터페이스 멤버 제약 사항
- 모든 멤버변수는
public static final
이어야 하며, 생략 가능
- 모든 메서드는
public abstract
이어야 하며, 생략 가능. 단, static 메서드와 디폴트 메서드는 예외(jdk 1.8부터)
- 원래는 인터페이스의 모든 메서드는 추상메서드이어야 하는데, JDK 1.8부터 인터페이스에 static 메서드와 디폴트 메서드의 추가를 허용하는 방향으로 변경됨
7.3 인터페이스의 상속
- 인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와 달리 다중상속이 가능
- 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속 받음
7.4 인터페이스의 구현
class 클래스이름 implements 인터페이스이름 {
}
- 인터페이스는 그 자체로는 인스턴스를 생성할 수 없음
- 인터페이스에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 하는데, 방법은 추상클래스가 자신을 상속받는 클래스를 정의하는 것과 같음
- 인터페이스는 구현한다는 의미의 키워드
implements
를 사용
- 인터페이스의 메서드 중 일부만 구현한다면,
abstract
를 붙여 추상클래스로 선언해야 함
class 클래스이름 extends 상속받을인터페이스이름 implements 구현할인터페이스이름{
...
}
7.6 인터페이스를 이용한 다형성
- 해당 인터페이스 타입의 참조변수로 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능
Fightable f = (Fightable)new Fight();
or
Fightable f = new Fighter();
- 인터페이스 Fightable을 클래스 Fighter가 구현했을 때, Fighter 인스턴스를 Fightable타입의 참조변수로 참조하는 것이 가능
- Fightable 타입의 참조변수로는 인터페이스 Fightable에 정의된 멤버들만 호출이 가능
- 인터페이스는 메서드의 매개변수의 타입으로 사용 가능
- 인터페이스 타입의 매개변수가 갖는 의미: 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야한다는 것
- 메서드의 리턴타입으로 인터페이스의 타입을 지정해주는 것도 가능
- 리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미
7.7 인터페이스의 장점
- 개발시간 단축
- 표준화 가능
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있음
- 독립적인 프로그래밍이 가능
1. 개발시간 단축
- 인터페이스가 작성되면, 이를 사용해 프로그램을 작성하는 것이 가능
- 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문
- 동시에 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하게 하면, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있음
2. 표준화 가능
- 프로젝트의 기본 틀을 인터페이스로 작성한 후, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 일관되고 정형화된 프로그램의 개발이 가능
3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있음
- 상속관계에 있지도 않고, 같은 조상 클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있음
4. 독립적인 프로그래밍이 가능
- 인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능
- 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해 간접적으로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능
7.8 인터페이스의 이해
- 클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있음
- 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언부만 알면 됨 (내용은 몰라도 됨)
7.9 디폴트 메서드와 static 메서드
- 인터페이스의 static 메서드는 접근 제어자가 항상 public이며, 생략 가능함
default 메서드
- 인터페이스에 메서드를 추가한다는 것은, 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 함
- 디폴트 메서드는 추상 메서드의 기본적인 구현을 제곻나는 메서드
- 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 됨
- 디폴트 메서드는 앞에 키워드
default
를 붙이며, 추상 메서드와 달리 일반 메서드처럼 몸통 {}이 있어야 함
- 디폴트 메서드는 접근 제어자가 public이며, 생략 가능함
- 새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생하는데, 충돌을 해결하는 규칙은 아래와 같음
1. 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 함
2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
- 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시됨
8. 내부 클리스(inner class)
8.1 내부 클래스람?
- 클래스 내에 선언된 클래스
- 클래스에 다른 클래스를 선언하는 이유는 두 클래스가 서로 긴밀한 관계에 있기 때문
내부 클래스 장점
- 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있음
- 코드의 복잡성을 줄일 수 있음 (캡슐화)
8.2 내부 클래스의 종류와 특징
내부 클래스 | 특징 |
---|
인스턴스 클래스(instance class) | 외부 클래스의 멤버변수 선언위치에 선언. 외부 클래스의 인스턴스멤버처럼 다뤄짐. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언됨 |
스태틱 클래스(static class) | 외부 클래스의 멤버변수 선언위치에 선언. 외부 클래스의 static 멤버처럼 다뤄짐. 주로 외부 클래스의 static 멤버, 특히 ststic 메서드에서 사용될 목적으로 선언됨 |
지역 클래스(local class) | 외부 클래스의 메서드나 초기화블럭 안에 선언. 선언된 영역 내부에서만 사용 가능 |
익명 클래스(anonymous class) | 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스 (일회용) |
8.4 내부 클래스의 제어자와 접근성
- 인스턴스클래스와 스태틱 클래스는 외부 클래스의 멤버변수와 같은 위치에 선언되며, 멤버변수와 같은 성질을 가짐
- 내부 클래스가 외부 클래스의 멤버와 같이 간주되고, 인스턴스 멤버와 static 멤버 간의 규칙이 내부 클래스에도 똑같이 적용됨
- 내부 클래스도 클래스기 때문에 abstract나 final 같은 제어자를 사용할 수 있고, 멤버변수들처럼 private, protected와 접근제어자도 사용 가능
- 내부 클래스 중 스태틱 클래스만 static 멤버를 가질 수 있음
- final과 static이 동시에 붙는 변수는 상수이므로 모든 내부 클래스에서 정의 가능
- 인스턴스 클래스는 외부 클래스의 인스턴스멤버를 객체생성 없이 바로 사용 가능하지만, 스태틱 클래스는 외부 클래스의 인스턴스멤버를 객체생성 없이 바로 사용 불가
- 인스턴스 클래스는 스태틱 클래스의 멤버들을 객체생성 없이 사용 가능하지만, 스태틱 클래스에서는 인스턴스 클래스의 멤버들을 객체생성 없이 사용 불가
8.5 익명 클래스(anonymous class)
new 조상클래스이름 () {
}
or
new 구현인터페이스이름 () {
}
- 클래스의 선언과 객체 생성을 동시에 하기 때문에 단 한번만 사용가능하고 하나의 객체만을 생성할 수 있는 일회용 클래스
- 이름이 없기 때문에 생성자를 가질 수 없으며, 조상클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없음
- 하나의 클래스를 상속받거나 하나의 인터페이스만 구현 가능
Chapter 7 끝!!!