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