Contents
RemoteControl.javaTelevision.javaAudio.javaRemoteConExam.java핵심 키워드Service.javaServiceImpl.javaServiceExample.java핵심 키워드RemoteCon.javaSearchable.javaSmartTelevision.javaSmartTelevisionImpl.javaMultipleInterfaceImplExample.java핵심 키워드Vehicle.javaBus.javaTaxi.javaBusExam.java핵심 키워드InterfaceA.javaInterfaceB.javaInterfaceC.javaImplClass.javaSealedExample.java핵심 키워드결론RemoteControl.java
package ch08; // tv 클래스와 audio 클래스의 사용법을 알려주는 것. public interface RemoteControl { int MAX_VOLUME = 10; int MIN_VOLUME = 0; void turnOn(); void turnOff(); void setVolume(int volume); void getVolume(); // 구현하는 클래스가 인스턴스를 만들었을 때 기본적으로 가지는 메소드 default void setMute(boolean mute) { if (mute) { System.out.println("무음 처리합니다."); setVolume(MIN_VOLUME); } else { System.out.println("무음 해제합니다."); } } static void chanegBattery() { System.out.println("리모콘 건전지를 교환합니다."); } }
Television.java
package ch08; public class Television implements RemoteControl{ private int volume; private int memoryVolume; @Override public void turnOn() { System.out.println("TV를 켭니다."); } @Override public void turnOff() { System.out.println("TV를 끕니다."); } @Override public void getVolume() { System.out.println(this.volume); } @Override public void setVolume(int volume) { if (volume > RemoteControl.MAX_VOLUME) { this.volume = RemoteControl.MAX_VOLUME; } else if (volume < RemoteControl.MIN_VOLUME) { this.volume = RemoteControl.MIN_VOLUME; } else { this.volume = volume; } System.out.println("현재 Audio volume: " + this.volume); } @Override public void setMute(boolean mute) { if(mute) { this.memoryVolume = this.volume; System.out.println("무음 처리합니다."); setVolume(MIN_VOLUME); }else { System.out.println("무음 해제합니다."); setVolume(this.memoryVolume); } } }
Audio.java
package ch08; public class Audio implements RemoteControl { private int volume; private int memoryVolume; @Override public void turnOn() { System.out.println("Audio를 켭니다."); } @Override public void turnOff() { System.out.println("Audio를 끕니다."); } @Override public void getVolume() { System.out.println(this.volume); } @Override public void setVolume(int volume) { if (volume > RemoteControl.MAX_VOLUME) { this.volume = RemoteControl.MAX_VOLUME; } else if (volume < RemoteControl.MIN_VOLUME) { this.volume = RemoteControl.MIN_VOLUME; } else { this.volume = volume; } System.out.println("현재 Audio volume: " + this.volume); } @Override public void setMute(boolean mute) { if(mute) { this.memoryVolume = this.volume; System.out.println("무음 처리합니다."); setVolume(MIN_VOLUME); }else { System.out.println("무음 해제합니다."); setVolume(this.memoryVolume); } } }
RemoteConExam.java
package ch08; public class RemoteConExam { public static void main(String[] args) { // 인터페이스 타입은 그 구현 클래스를 모두 담을 수 있음 // 그 타입에 명시된 메서드만 visible함. RemoteControl rc; // 인터페이스는 설계도의 개념이라 구현할 수 없다. // RemoteControl rc = new RemoteControl(); 같은 표현은 틀린 것. // rc라는 객체는 인터페이스에게 메소드를 호출하면 인터페이스가 알아서 리턴값을 맞게 돌려주는 것 rc = new Television(); rc.turnOn(); rc.setVolume(5); rc.turnOff(); rc.setMute(true); rc.setMute(false); System.out.println(""); rc= new Audio(); rc.turnOn(); rc.setVolume(11); rc.turnOff(); rc.setMute(true); rc.setMute(false); System.out.println(""); RemoteControl.chanegBattery(); } }
핵심 키워드
- 인터페이스의 선언은 interface 키워드를 사용하며, 접근 제한자로는 default, public을 붙일 수 있다.
- implements 키워드를 통해 해당 클래스가 인터페이스를 구현할 수 있다.
- 인터페이스에 선언된 필드는 모두 public static final 특성을 가진다.
- 인터페이스는 구현 클래스가 재정의해야 하는 public 추상 메소드를 멤버로 가질 수 있다.
- 추상 메소드는 리턴 타입, 메소드명, 매개변수만 기술되고 {}를 붙이지 않는다.
- 인터페이스는 완전한 실행 코드를 가진 디폴트 메소드를 가질 수 있다.
- 선언 방법은 default 키워드를 앞에 붙이는 것이다.
- 인터페이스는 정적 메소드도 선언이 가능하다. 정적 메소드는 구현 객체가 없어도 인터페이스 만으로 호출이 가능하다.
- 선언 방법은 클래스 정적 메소드와 동일하다.
Service.java
package ch08; public interface Service { // 인터페이스-구현-인터페이스화 해야 사용할 수 있는 메서드. 반드시 구현 객체를 만들어야 한다. default void defaultMethod1() { System.out.println("defaultMethod1 종속 코드"); defaultCommon(); } default void defaultMethod2() { System.out.println("defaultMethod2 종속 코드"); defaultCommon(); } private void defaultCommon() { System.out.println("defaultMethod 종속 코드 A"); System.out.println("defaultMethod 종속 코드 B"); } static void staticMethod1() { System.out.println("staticMethod1 종속 코드"); staticCommon(); } static void staticMethod2() { System.out.println("staticMethod2 종속 코드"); staticCommon(); } static void staticCommon() { System.out.println("staticMethod 종속 코드 C"); System.out.println("staticMethod 종속 코드 D"); } }
ServiceImpl.java
package ch08; public class ServiceImpl implements Service{ }
ServiceExample.java
package ch08; public class ServiceExample { public static void main(String[] args) { Service service = new ServiceImpl(); service.defaultMethod1(); System.out.println(); service.defaultMethod2(); System.out.println(); Service.staticMethod1(); System.out.println(); Service.staticMethod2(); System.out.println(); } }
핵심 키워드
- private 메소드는 디폴트 메소드 안에서만 호출이 가능하고, private 정적 메소드는 정적 메소드 안에서도 호출이 가능하다.
RemoteCon.java
package ch08; public interface RemoteCon { void turnOn(); void turnOff(); }
Searchable.java
package ch08; public interface Searchable { void search(String url); }
SmartTelevision.java
package ch08; public interface SmartTelevision extends RemoteCon, Searchable{ }
SmartTelevisionImpl.java
package ch08; public class SmartTelevisionImpl implements SmartTelevision { @Override public void turnOn() { System.out.println("TV를 켭니다."); } @Override public void turnOff() { System.out.println("TV를 끕니다."); } @Override public void search(String url) { System.out.println(url + "을 검색합니다."); } }
MultipleInterfaceImplExample.java
package ch08; public class MultipleInterfaceImplExample { public static void main(String[] args) { RemoteCon rc = new SmartTelevisionImpl(); rc.turnOn(); rc.turnOff(); Searchable searchable = new SmartTelevisionImpl(); searchable.search("https://www.youtube.com"); SmartTelevision st = new SmartTelevisionImpl(); st.turnOn(); st.turnOff(); st.search("https://www.youtube.com"); } }
핵심 키워드
- 구현 객체는 여러 개의 인터페이스를 implements 할 수 있다. 구현 객체가 여러 인터페이스를 구현하고 있다면, 각각의 인터페이스를 통해 구현 객체를 사용할 수 있다.
- 구현 객체가 어떤 인터페이스 변수에 대입되느냐에 따라 변수를 통해 호출할 수 있는 추상 메소드가 결정된다.
Vehicle.java
package ch08; public interface Vehicle { void run(); }
Bus.java
package ch08; public class Bus implements Vehicle{ @Override public void run() { System.out.println("버스가 달립니다."); } public void checkFare() { System.out.println("승차요금을 체크합니다."); } }
Taxi.java
package ch08; public class Taxi implements Vehicle{ @Override public void run() { System.out.println("택시가 달립니다."); } }
BusExam.java
package ch08; public class BusExam { public static void main(String[] args) { Vehicle vehicle = new Bus(); vehicle.run(); // vehicle.checkFare(); // non-visable 하기 떄문 System.out.println(); Bus bus = (Bus)vehicle; bus.run(); bus.checkFare(); System.out.println(); Vehicle taxi = new Taxi(); ride(taxi); ride(bus); } static void ride(Vehicle v) { v.run(); // v.checkFare(); // Bus에는 있지만 Vehicle 에는 없기 때문에 non-visible if(v instanceof Bus b) { // 따라서 instanceof 사용. b.checkFare(); } } }
핵심 키워드
- 강제 타입 변환은 캐스팅 기호를 사용해서 인터페이스 타입을 구현 클래스 타입으로 변환시키는 것이다.
- 구현 객체가 인터페이스 타입으로 자동 변환되면, 인터페이스에 선언된 메소드만 사용 가능하다.
- 만약 자동 타입 변환 후에 non-visible해진 메소드를 사용하고 싶다면 캐스팅 기호를 사용해서 원래 타입으로 강제 타입 변환해야 한다.
InterfaceA.java
package ch08; // sealed를 인터페이스에 쓰면 구현을 막는게 아닌 상속을 막는 것 public sealed interface InterfaceA permits InterfaceB{ void methodA(); }
InterfaceB.java
package ch08; public non-sealed interface InterfaceB extends InterfaceA{ void methodB(); }
InterfaceC.java
package ch08; public interface InterfaceC extends InterfaceB{ void methodC(); }
ImplClass.java
package ch08; public class ImplClass implements InterfaceC{ @Override public void methodB() { System.out.println("methodB 실행"); } @Override public void methodA() { System.out.println("methodA 실행"); } @Override public void methodC() { System.out.println("methodC 실행"); } }
SealedExample.java
package ch08; public class SealedExample { public static void main(String[] args) { ImplClass impl = new ImplClass(); InterfaceA ia = impl; ia.methodA(); InterfaceB ib = impl; ib.methodA(); ib.methodB(); InterfaceC ic = impl; ic.methodA(); ic.methodB(); ic.methodC(); } }
핵심 키워드
- 인터페이스도 다른 인터페이스를 상속할 수 있으며, 클래스와는 달리 다중 상속을 허용한다.
- 부모 클래스가 인터페이스를 구현하고 있다면 자식 클래스도 인터페이스 타입으로 자동 타입 변환된다. 또한 자식 객체는 부모 객체로 자동 변환될 수 있다.
- 인터페이스 타입을 구현 클래스 타입으로 변환할 때는 강제 타입 변환이 필요하다.
- 자바 15부터는 무분별한 자식 인터페이스 생성을 방지하기 위해 sealed 인터페이스를 사용할 수 있다.
- sealed 키워드를 사용하면 permits 키워드 위에 상속 가능한 자식 인터페이스를 지정해야 한다.
- 자식 인터페이스는 non-sealed 키워드를 사용해서 선언하거나, 또는 sealed 키워드를 사용해서 또 다른 봉인 인터페이스로 선언해야 한다.
결론
해당 문제를 풀면서 자바에서 인터페이스가 가지는 역할과 그 기능을 익힐 수 있었다.
Share article