
interface 인터페이스명 {...} //default 접근 제한
public interface 인터페이스명 {...} //public 접근 제한
public interface RemoteCtrl{
//public 추상 메소드
public void turnOn();
}
객체 B같은 구현 객체는 인터페이스를 구현하고 있다고 선언부에 명시해야 한다
public class B implements 인터페이스명 {...}
public class Television implements RemoteCtrl{
@override
public void turnOn(){
System.out.println("TV ON");
}
}
public class Audio implements RemoteCtrl{
@override
public void turnOn(){
System.out.println("Audio ON");
}
}
public class RemoteCtrlEx{
public static void main(String[] args){
RemoteCtrl rc;
//rc 변수에 Television 객체를 대입
rc = new Television();
rc.turnOn();
//rc 변수에 Audio 객체를 대입(교체)
rc = new Audio();
rc.turnOn();
}
}
>> TV ON
>> Audio ON
public interface RemoteCtrl{
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
}
public class RemoteCtrlEx{
public static void main(String[] args){
System.out.println(RemoteCtrl.MAX_VOLUME);
}
}
public interface RemoteCtrl{
//상수 필드
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
//추상 메소드
void turnOn();
void turnOff();
void setVolume(int volume);
}
⚠️ 구현 클래스에서 추상 메소드를 재정의 할 때, 인터페이스의 추상 메소드는 기본적으로 public 접근제한을 갖기 때문에 더 낮은 제한으로 재정의 불가능하다. 그래서 재정의한 메소드에 public이 추가되어 있다. (public void turnOn())
public class Television implements RemoteCtrl{
//필드
private int volume;
//turnOn() 추상 메소드 오버라이딩
@override
public void turnOn(){
System.out.println("TV ON");
}
}
[public] default 리턴타입 메소드명(매개변수, ...){}
default void setMute(boolean mute){
if(mute){
//추상 메소드 호출하면서 상수 필드 사용
setVolume(MAX_VOLUME);
}
else{
System.out.println("MUTE");
}
}
구현 클래스에서 디폴트 메소드를 재정의해서 쓸 수도 있다. 재정의 할 때, public 접근 제한자를 반드시 붙여야하고 default 키워드를 생략해야한다.
private int memoryVolume; //추가 필드 선언
@Override
public void setMute(boolean mute){
if(mute){
//추상 메소드 호출하면서 상수 필드 사용
setVolume(MAX_VOLUME);
}
else{
System.out.println("MUTE");
}
}
[public | private] static 리턴타입 메소드명(매개변수, ...) {...}
static void changeBattery(){
System.out.println("Change Battery");
}
//main
RemoteControl.changeBattery();
| 구분 | 설명 | 호출 범위 |
|---|---|---|
| private 메소드 | 구현 객체가 필요한 메소드 | 디폴트 메소드 안에서만 호출 |
| private 정적 메소드 | 구현 객체가 필요 없는 메소드 | 디폴트 메소드 + 정적 메소드 안에서 호출 |
private interface Service{
//default 메소드
default void defaultMethod(){
defaultCommon();
}
// private 메소드
private void defaultCommon(){
System.out.println("defaultMethod 중복 A");
}
//정적 메소드
static void staticMethod(){
staticCommon();
}
//private 정적 메소드
private static void staticCommon(){
System.out.println("staticMethod 중복C");
}
}
public class 구현클래스명 implements 인터페이스A, 인터페이스B{
//모든 추상 메소드 재정의
}
public interface RemoteControl{
//추상 메소드
void turnOn();
void turnOff();
}
public interface Searchable{
//추상 메소드
void search(String url);
}
public class SmartTelevision implements RemoteControl, Searchable{
//turnOn() 추상 메소드 오버라이딩
@Override
public void turnOn(){}
//turnOff() 추상 메소드 오버라이딩
public void turnOff(){}
//search() 추상 메소드 오버라이딩
@Override
public void search(String url){}
}
//main
RemoteControl rc = new SmartTelevision();
rc.turnOn();
rc.turnOff();
Searchable searchable = new SmartTelevision();
searchabl.search("https://youtube.com");
→ 오버라이딩 한 내용으로 결과값 출력됨
public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 {...}
public interface InterfaceA{
void methodA();
}
public interface InterfaceB{
void methodB();
}
public interface InterfaceC extends InterfaceA, InterfaceB{
void methodC();
}
public class InterfaceCImpl implements InterfaceC{
public void methodA(){}
public void methodB(){}
public void methodC(){}
}
//main
InterfaceCImpl impl = new InterfaceCImpl();
InterfaceA ia = impl;
ia.methodA(); //A만 호출 가능
InterfaceB ia = impl;
ia.methodB(); //B만 호출 가능
InterfaceC ia = impl;
ia.methodA();
ia.methodB();
ia.methodC();
B b = new B();
C c = new C();
A a;
a = b;
a = c
public interface Vehicle{
void run();
}
public class Bus implements Vehicle{
@Override
public void run(){}
//추가 메소드
public void checkFare(){}
}
//main
//인터페이스 변수 선언과 구현 객체 대입
Vehicle vehicle = new Bus();
//인터페이스를 통해서 호출
vehicle.run();
//vehicle.checFare(); 사용불가
//강제 타입 변환 후 호출
Bus bus = (Bus) vehicle;
bus.run();
bus.checkFare();
아래처럼 필드 타입으로 타이어 인터페이스를 선언하면, 자동 타입 변환에 의해 필드값으로 한국타이어 또는 금호타이어 객체를 대입할 수 있다.
public class Car{
Tire tire1 = new HankookTire();
Tire tire2 = new KumhoTire();
}
Car 객체를 생성한 후 다른 구현 객체를 대입할 수 있다. (타이어 교체)
Car myCar = new Car();
myCar.tire1 = new KumhoTire();
void drive(Vehicle vehicle){
vehicle.run();
}
public class Driver{
void drive(Vehicle vehicle){
vehicle.run();
}
}
if(vehicle instanceof Bus bus){ //vehicle에 대입된 객체가 Bus일 경우 실행
//bus 변수 사용
}
sealed를 사용하면 permits 뒤에 상속 가능한 자식 인터페이스를 지정해야 한다.
public sealed interface InterfaceA permits InterfaceB {...}
//봉인 해제. 다른 자식 인터페이스 생성 가능
public non-sealed interface InterfaceB extends InterfaceA {...}
// 봉인. 또 다른 봉인 인터페이스 선언
public sealed interface InterfaceB extends InterfaceA {...}
이것이 자바다(신용권, 임경균 지음)