일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Lv.0
- JPA
- Join
- 이것이 자바다
- 알고리즘
- 데이터 베이스
- Til
- mysql
- LV1
- Redis
- LV03
- Spring Frame Work
- LV.02
- 프로그래머스
- LV01
- 일정관리프로젝트
- 연습문제
- Java
- SQL
- LV02
- jpa blog
- 포트폴리오
- 네트워크
- 코테
- CoffiesVol.02
- 디자인 패턴
- 배열
- LV0
- docker
- 포트 폴리오
- Today
- Total
코드 저장소.
[이것이 자바다] Chapter8장 인터페이스 본문
신용권 님의 ''이것이 자바다'' 8장 공부 기록
8.인터페이스
8.1. 인터페이스란?
인터페이스 는 객체의 사용방법을 정의하는 타입을 말한다.
- 인터페이스는 다형성을 구현하는 매우 중요한 역할을 한다.
8.2. 인터페이스 선언
인터페이스는 선언은 class 대신에 interface키워드를 사용한다.
[public] interface 인터페이스명{
//상수
타입 상수명 = 값;
//추상 메서드
타입 메소드명(매개변수..);
//디폴트 메서드
default 타입 메서드(매개변수,....){...}
//정적 메서드
static 타입 메소드명(매개변수){...}
- 상수 필드
- 인터페이스는 런타입 시 데이터를 저장할 수 있는 필드를 선언을 할 수 없다.
- 상수는 이터페이스에 고정된 값으로 런타임 시에 데이터를 바꿀 수 없다.
- 상수를 선언할 때에는 반드시 초기값을 대입해야 한다.
[public static final] 타입 상수명 = 값;
- 추상 메서드
- 객체가 가지고 있는 메소드를 설명한 메소드이다.
- 호출할 때 어떤 매개값이 필요하고,리턴 타입이 무엇인지만 알려준다.
- 구체적인 내용은 구현객체가 각지고 있다.
[public abstract] 리턴타입 메소드명(매개변수....);
- 디폴트 메서드
- 구현 객체가 가지고 있는 인스턴스 메소드이다.
- 기존 인터페이스를 확장해서 새로운 기능을 호출이 가능하다.
[public] default 리턴타입 메소드명(매개변수,...){...}
- 정적 메서드
- 정적 메서드는 객체가 없어도 인터페이스만으로 호출이 가능하다.
[public] static 리턴타입 메소드명(매개변수,...){...}
8.3.인터페이스 구현
8.3.1. 구현 클래스
public class 구현클래스명 implements 인터페이스명{
//인터페이스에 선언된 추상 메서드의 실체 메소드 선언
}
구현 클래스에서 인터페이스의 추상 메소드에 대한 실체 메소드를 구현할 때 주의할 점은 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 떄문에 public 보다 낮은 접근 제한으로 작성할 수 없다. 그리고 public을 생략한 경우에는 "Cannot reduce the visibility of the inherited method(상속된 메소드의 가시성을 줄일 수 없다)" 컴파일 에러가 발생한다.
이런 경우에는 인터페이스에 선언된 추상 메소드에 대응하는 실체 메소드를 구현 클래스가 작성하지 않으면 구현 클래스는 자동적으로 추상 클래스가 된다.
public abstract class Television implements RemoteControl{
//실체 메소드를 작성하지 않음
public void turnOn(){}
public void turnOff(){}
}
- 구현 클래스의 실체 메소드에 @Override 어노테이션을 붙이면 컴파일러가 실체 메소드인지를 체크한다.
- 구현 클래스가 작성되면 new 연산자로 객체를 생성하여 인터페이스에 대입할 수 있다. 인터페이스 변수는 참조 타입이므
로 구현객체의 번지를 저장한다.
8.3.2.익명 클래스 구현
인터페이스 변수 = new 인터페이스{
//인터페이스에 선언된 추상 메소드의 실제 메소드 선언
}
-중괄호에는 인터페이스에 선언된 모든 추상 메소드들의 실체 메소드를 작성해야 한다. 그렇지 않으면 컴파일 에러가 발생한다.
-추가적으로 필드와 메소드 선언이 가능하나, 익명 객체 안에서만 사용할 수 있고 인터페이스 변수로 접근할 수 없다.
-모든 객체는 클래스로부터 생성된다. 익명 구현 객체의 소스코드를 컴파일하면 컴파일러에 의해 "클래스명$1.class"의 이름으로 파일이 생성된다.
8.3.3.다중 인터페이스 구현 클래스
public class 구현 클래스 implements 인터페이스A,인터페이스B{
//인터페이스A에 선언된 추상 메소드의 실체 메소드 선언
//인터페이스B에 선언된 추상 메소드의 실체 메소드 선언
}
객체는 다수의 인터페이스 타입으로 사용할 수 있다.
8.4.타입 변환과 다형성
클래스에 문제가 있어 다른 클래스를 만들 때는 같은 메소드를 사용한다면 메소드 선언부가 동일해야 한다. 인터페이스를 추상 메소드를 작성하고 구현 클래스로 해당 메소드를 작성할 시에 이러한 문제를 해결할 수 있다. 처음부터 메소드 선언부가 동일하기 때문이다.
인터페이스는 메소드의 매개 변수로 많이 등장하는데, 해당 매개 값으로 여러 종류의 구현 객체를 줄 수 있으므로 메소드 실행 결과가 다양하게 나온다. 이것이 인터페이스 매개 변수의 다형성이다.
8.4.1.자동 타입 변환(Promotion)
인터페이스 변수(자동 타입 변환) = 구현 객체;
구현 클래스를 상속하여 자식 클래스를 만들었다면 자식 객체 역시 인터페이스 타입으로 자동 타입 변환시킬 수 있다. 이를 통해 필드의 다형성과 매개 변수의 다형성을 구현할 수 있다.
8.4.2.필드의 다형성
같은 인터페이스의 구현 객체는 교체될 수 있다. 따라서 개발 코드의 수정 없이도 다양한 결과(개발 코드에서의 인터페이스 메소드 실행 등)를 얻을 수 있다.
8.4.3.인터페이스 배열로 구현 객체 관리
인터페이스 배열을 통해 여러 구현 객체들을 인덱스로 표현하여 관리할 수 있다. 이렇게 하면 제어문에서 가장 큰 이점이 있다.
Tire[] tires ={
new HTire();
new HTire();
new HTire();
new HTire();
}
void run(){
for(Tire tire : tires){
tire.roll();
}
}
8.4.4 매개 변수의 다형성
- 자동 타입 변환은 주로 메소드를 호출할 때 많이 발생한다. 매개 변수를 인터페이스 타입으로 선언하고 호출 시 구현 객체를 대입한다.
//Driver 클래스
public class Driver{
public void drice(Vehicle vehicle){
vehicle.run();
}
}
//Vehicle 인터페이스 타입
public interface Vehicle{
public void run();
}
//구현 객체 Bus
public class Bus implements Vehicle{
@Override
public void run(){
System.out.println("버스가 달립니다");
}
}
//매개 변수의 다형성 테스트
public class DriverEx{
public static void main(String[] args){
Driver driver = new Driver()
Bus bus = new Bus();
driver.drive(bus);//bus ->자동 타입 변환됨
}
}
- 인터페이스가 매개변수 타입으로 제공될 경우, 어떠한 구현 객체도 매개값으로 사용할 수 있고, 이를 통해 메소드의 실행결과가 다양해질 수 있게 된다.(매개 변수의 다형성)
8.4.5 강제 타입 변환
- 구현 객체가 인터페이스 타입으로 자동 변화하면, 인터페이스에 선언된 메소드만 사용이 가능하다. 그러나 경우에 따라 구현 클래스에 선언된 필드와 메소드를 사용해야 할 수 있는데, 이 때 강제 타입 변환을 사용하여 구현 클래스의 필드와 메소드를 사용할 수 있다.
구현 클래스 변수 = (구현 클래스) 인터페이스 변수;//강제 타입 변환
8.4.6 객체 타입 확인
- 강제 타입변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능하다. 이 때 상속에서 객체 타입 확인을 한 것처럼, 인터페이스 타입도 객체의 타입 확인이 필요하다. 어떤 구현 객체가 변환되어 있는지 알지 못하고 변환할 경우 ClassCastException이 발생할 수 있기 때문이다.
- 객체 타입 확인을 위하여 instanceof 연산자를 사용할 수 있다.
if(vehicle instanceof Bus){
Bus bus = (Bus) vehicle; //안심하고 변환 가능
}
8.5 인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있다. 인터페이스는 클래스와 달리 다중 상속을 허용한다.
public interface 하위인터페이스 extends 상위인터페이스1, 하위인터페이스2 {...}
하위 인터페이스의 구현 클래스는 하위, 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 한다. 따라서 해당 구현 클래스로부터 객체를 생성하고 나서 하위 및 상위 인터페이스 타입으로 변환이 가능하다.
하위인터페이스 변수 = new 구현클래스(...);
상위인터페이스1 변수 = new 구현클래스(...);
상위인터페이스2 변수 = new 구현클래스(...);
하위 인터페이스로 타입 변환이 되면 상하위 인터페이스에 선언된 모든 메소드를 사용할 수 있으나, 상위 인터페이스로 타입 변환시 하위 인터페이스에 선언된 메소드는 사용이 불가하다.
8.6 디폴트 메소드와 인터페이스 확장
디폴트 메소드는 인터페이스에서 선언된 인스턴스 메소드이므로 구현 객체가 있어야 사용가능하다. 왜 선언은 인터페이스에서 하고, 사용은 구현 객체를 통해 하는 것일까?
8.6.1 디폴트 메소드의 필요성
인터페이스에서 디폴트 메소드가 필요한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다.
- 추상 클래스는 구현 클래스에서 실행 내용을 채워야 하지만, 디폴트 메소드는 인터페이스에 정의된 것을 그냥 사용해도 되고, 필요에 따라 재정의해서 사용할 수도 있다.
8.6.2 디폴트 메소드가 있는 인터페이스 상속
- 부모 인터페이스에 디폴트 메소드가 정의되어 있을 경우, 자식 인터페이스에서 디폴트 메소드를 활용하는 방법은 다음 세 가지가 있다.
- 디폴트 메소드를 단순히 상속만 받는다.
//부모 인터페이스
public interface ParentInterface{
public void method1();
public default void method2(){/*실행문*/}
}
//자식 인터페이스1
public interface ChildInterface1 extends ParentInterface {
public void method3;
}
//자식 인터페이스1을 구현하는 클래스는 method1()과 method3()의 실체 메소드를 가지고 있어야 하며 method2()를 호출할 수 있다.
ChildInterface1 ci1 = new ChildInterface1(){ //익명 구현 객체
@Override
public void method1() {/*실행문*/}
@Override
public void method3() {/*실행문*/}
};
ci1.method1();
ci1.method2();//ParentInterface의 method2() 호출
- 디폴트 메소드를 재정의(Override)해서 실행 내용을 변경한다.
//자식 인터페이스2
public interface ChildInterface2 extends ParentInterface {
@Override
public default void method2() {/*실행문*/} //재정의
public void method3();
}
//자식 인터페이스1 구현 클래스와 유사함.
ChildInterface2 ci2 = new ChildInterface2(){ //익명 구현 객체
@Override
public void method1() {/*실행문*/}
@Override
public void method3() {/*실행문*/}
};
ci2.method1();
ci2.method2();//ParentInterface의 method2() 호출
- 디폴트 메소드를 추상 메소드로 재선언한다.
//자식 인터페이스3
public interface ChildInterface3 extends ParentInterface {
@Override
public void method2() //추상 메소드로 재선언
public void method3();
}
//자식 인터페이스3을 구현하는 클래스는 method1(), method2(), method3()의 실체 메소드를 모두 가지고 있어야 한다.
ChildInterface2 ci3 = new ChildInterface3(){ //익명 구현 객체
@Override
public void method1() {/*실행문*/}
@Override
public void method2() {/*실행문*/}
@Override
public void method3() {/*실행문*/}
};
ci3.method1();
ci3.method2();//ChildInterface3 구현 객체의 method2() 호출
'Java' 카테고리의 다른 글
[이것이 자바다] Chpater06. 확인문제 (0) | 2023.03.15 |
---|---|
[이것이 자바다] Chapter10장 예외 처리 (0) | 2023.02.20 |
[이것이 자바다] Chapter9장 중첩 클래스와 중첩 인터페이스 (0) | 2023.02.19 |
[이것이 자바다] Chapter7장 상속 (0) | 2023.02.17 |
[이것이 자바다] Chapter6장 클래스 (0) | 2023.01.30 |