두 객체를 연결하는 역할을 함

// 인터페이스 선언
// public 또는 default 형태로 접근이 가능함
public interface 인터페이스명{
public 메소드{ // abstract 생략 가능
// 선언 가능한 메소드/필드 종류
// public 상수 필드
// public 추상 메소드
// public 디폴트 메소드
// public 정적 메소드
// private 메소드
// private 정적 메소드
}
}
package ch08.sec02;
// 인터페이스 선언
public interface RemoteControl {
// 추상 메소드 선언 (abstract 생략 가능)
public void turnOn();
}
// 구현 클래스 선언
public class 클래스명 implements 인터페이스명
public void 메소드명() {
// 인터페이스에서 선언한 메소드를 해당 클래스에서 구현
// 해당 클래스에서 메소드를 선언하지 않으면 오류가 남
}
}
package ch08.sec02;
// implements : 인터페이스를 가져오는 역할 (extends와 기능 비슷함)
public class Television implements RemoteControl{
// 인터페이스에서 선언한 메소드를 꼭 실행문을 넣어 실행시켜야함
@Override
public void turnOn() {
System.out.println("TV를 켭니다");
}
}
package ch08.sec02;
//implements : 인터페이스를 가져오는 역할 (extends와 기능 비슷함)
public class Audio implements RemoteControl{
// 인터페이스에서 선언한 메소드를 꼭 실행문을 넣어 실행시켜야함
@Override
public void turnOn() {
System.out.println("Audio를 켭니다");
}
}
package ch08.sec02;
public class RemoteControlExam {
public static void main(String[] args) {
RemoteControl rc;
// 인터페이스 참조변수를 선언
// 객체를 생성할 수 없기 때문에 인터페이스를 구현한
// 클래스의 객체를 참조만 가능
rc = new Television();
// Television 객체 생성
rc.turnOn();
// TV를 켭니다
rc = new Audio();
// Audio 객체 생성
rc.turnOn();
// Audio를 켭니다
}
}
package ch08.sec03;
public interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
// 인터페이스에서는 private static 생략이 가능
// 상수를 입력할 때에는 대문자와 언더바(_) 조합으로 작성
}
인터페이스
package ch08.sec04;
public interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
// 상수 선언
void turnOn();
void turnOff();
void setVolume(int volume);
// 메소드 선언 시 추상 메소드와 동일하게 메소드 선언부만 작성
// 실행문 동작은 구현 객체에서 함
// 접근 방식이 없을 경우 public의 역할을 함
}
구현 클래스 (Television)
package ch08.sec04;
public class Television implements RemoteControl{
// 인터페이스를 불러오기 위해서는 implements 키워드 사용
// 인터페이스에서 추상 메소드를 사용하였음
// 추상 메소드를 가지는 인터페이스를 사용하는 클래스에서
// 추상 메소드를 다 선언하지 않으면 오류가 남
private int volume;
public void turnOn() {
System.out.println("TV를 켭니다");
}
public void turnOff() {
System.out.println("TV를 끕니다");
}
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("현재 TV 볼륨");
}
}
구현 클래스 (Audio)
package ch08.sec04;
public class Audio implements RemoteControl{
// 인터페이스를 불러오기 위해서는 implements 키워드 사용
// 인터페이스에서 추상 메소드를 사용하였음
// 추상 메소드를 가지는 인터페이스를 사용하는 클래스에서
// 추상 메소드를 다 선언하지 않으면 오류가 남
private int volume;
public void turnOn() {
System.out.println("Audio를 켭니다");
}
public void turnOff() {
System.out.println("Audio를 끕니다");
}
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 볼륨");
}
}
실행 클래스
package ch08.sec04;
public class RemoteControlExam {
public static void main(String[] args) {
RemoteControl rc;
// 인터페이스는 직접 객체 생성이 불가능함
// 따라서 참조변수 형태로만 선언이 가능
// 구현 객체를 생성하여 인터페이스 참조변수에 대입하여 사용
rc = new Television();
rc.turnOn();
rc.setVolume(5);
rc.turnOff();
// Television 객체에서 재정의한 메소드가 실행됨
rc = new Audio();
rc.turnOn();
rc.setVolume(5);
rc.turnOff();
// Audio 객체에서 재정의한 메소드가 실행됨
}
}
인터페이스
package ch08.sec05;
public interface RemoteControl {
// 상수 선언
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
// 추상 메소드 선언
void turnOn();
void turnOff();
void setVolume(int volume);
// 디폴트 메소드 : 인터페이스에서 메소드 실행 코드를 작성하기 위함
// 앞에 default를 꼭 적어주고, 중괄호(실행 블록)를 꼭 선언해줘야함
// 접근 방식은 default 앞에 적는데, 없으면 public!
default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다");
setVolume(MIN_VOLUME);
}
else {
System.out.println("무음 해제합니다");
}
}
}
구현 클래스에서 디폴트 메소드 재정의
package ch08.sec05;
public class Audio implements RemoteControl{
// 인터페이스를 불러오기 위해서는 implements 키워드 사용
// 인터페이스에서 추상 메소드를 사용하였음
// 추상 메소드를 가지는 인터페이스를 사용하는 클래스에서
// 추상 메소드를 다 선언하지 않으면 오류가 남
private int volume;
public void turnOn() {
System.out.println("Audio를 켭니다");
}
public void turnOff() {
System.out.println("Audio를 끕니다");
}
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);
}
private int memoryVolume;
// 음소거 이전 볼륨을 저장함
// 인터페이스에서 선언한 디폴트 메소드 재정의
@Override
public void setMute(boolean mute) {
if(mute) {
this.memoryVolume = this.volume;
// 해당 클래스의 volume 필드에 저장된 값을 위의 memoryVolume 필드에 저장
System.out.println("무음 처리함");
setVolume(RemoteControl.MIN_VOLUME);
// 인터페이스에서 선언한 상수 호출
}
else {
System.out.println("무음 해제합니다");
setVolume(this.memoryVolume);
// 이전에 설정한 볼륨값 기억
}
}
}
실행 클래스
package ch08.sec05;
public class RemoteControlExam {
public static void main(String[] args) {
RemoteControl rc;
// 인터페이스는 객체로 생성 불가능, 참조변수로만 가능
// 인터페이스 참조변수에 Television 객체 대입
rc = new Television();
rc.turnOn();
rc.setVolume(5);
// 디폴트 메소드를 호출함
rc.setMute(true);
rc.setMute(false);
// 인터페이스 참조 변수에 Audio 객체 대입
rc = new Audio();
rc.turnOn();
rc.setVolume(6);
// 디폴트 메소드를 호출함
rc.setMute(true);
rc.setMute(false);
}
}
인터페이스
package ch08.sec06;
public interface RemoteControl {
// 상수 선언
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
// 추상 메소드 선언
void turnOn();
void turnOff();
void setVolume(int volume);
// 디폴트 메소드
default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다");
setVolume(MIN_VOLUME);
}
else {
System.out.println("무음 해제합니다");
}
}
// 정적 메소드
// 정적 메소드에는 정적 필드만 사용 가능
// 접근 권한 명시되어있지 않으면 public
static void changeBattery() {
System.out.println("리모콘 건전지를 교체합니다.");
}
}
실행 클래스
package ch08.sec06;
public class RemoteControlExam {
public static void main(String[] args) {
RemoteControl rc;
// 인터페이스는 객체로 생성 불가능, 참조변수로만 가능
// 인터페이스 참조변수에 Television 객체 대입
rc = new Television();
rc.turnOn();
rc.setVolume(5);
// 디폴트 메소드를 호출함
rc.setMute(true);
rc.setMute(false);
// 인터페이스 참조 변수에 Audio 객체 대입
rc = new Audio();
rc.turnOn();
rc.setVolume(6);
// 디폴트 메소드를 호출함
rc.setMute(true);
rc.setMute(false);
// 정적 메소드
// 정적 메소드는 인터페이스 구현 객체 없이 바로 생성 가능
RemoteControl.changeBattery();
}
}
인터페이스
package ch08.sec07;
public interface Service {
// 디폴트 메소드
default void defaultMethod1() {
System.out.println("defaultMethod1 종속 코드");
defaultCommon();
// private 메소드를 선언하여 외부에서도 사용 가능하게 함
}
default void defaultMethod2() {
System.out.println("defaultMethod2 종속 코드");
defaultCommon();
}
// private 메소드는 외부에서 사용이 불가능
// 따라서 위의 디폴트 메소드를 통해 해당 private 메소드를 실행 할 수 있음
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();
}
// private 메소드는 외부에서 사용이 불가능
// private 메소드는 외부에서 사용이 불가능
// 따라서 위의 정적 메소드를 통해 해당 private 메소드를 실행 할 수 있음
// 정적 메소드이기 때문에 static을 꼭 붙여주기
private static void staticCommon() {
System.out.println("staticMethod 중복 코드A");
System.out.println("staticMethod 중복 코드B");
}
}
인터페이스
package ch08.sec08;
public class SmartTelevision implements RemoteControl, Searchable{
// 인터페이스를 두 개 이상 가져옴으로서 다중 인터페이스 구현이 가능하다
// 가져오는 인터페이스들의 추상 메소드를 모든 불러와야 에러가 안뜸
// RemoteControl 인터페이스의 메소드 선언
@Override
public void turnOn() {
System.out.println("TV를 켭니다");
}
// RemoteControl 인터페이스의 메소드 선언
@Override
public void turnOff() {
System.out.println("TV를 끕니다");
}
// Searchable 인터페이스의 메소드 선언
@Override
public void search(String url) {
System.out.println(url + "을 검색합니다");
}
}
인터페이스 A
package ch08.sec09;
public interface InterfaceA {
void methodA();
// 추상 메소드를 선언함
}
인터페이스 B
package ch08.sec09;
public interface InterfaceB {
void methodB();
// 추상 메소드를 선언함
}
인터페이스 C (인터페이스 A와 B를 상속받음)
package ch08.sec09;
public interface InterfaceC extends InterfaceA, InterfaceB {
// 인터페이스는 상속받을 때 다중 상속을 허용함
void methodC();
}
인터페이스 구현 객체
package ch08.sec09;
public class InterfaceCImpl implements InterfaceC{
// InterfaceC의 인터페이스를 사용
// 상속 받은 인터페이스의 추상 메소드의 실행문을 만들어야함
public void methodA() {
System.out.println("A");
}
public void methodB() {
System.out.println("B");
}
public void methodC() {
System.out.println("C");
}
}
실행 클래스
package ch08.sec09;
public class ExtendsExam {
public static void main(String[] args) {
InterfaceCImpl impl = new InterfaceCImpl();
// 인터페이스의 구현 객체를 생성
// 인터페이스A의 참조변수에 구현 객체를 대입함
InterfaceA ia = impl;
ia.methodA();
System.out.println();
// 인터페이스B의 참조변수에 구현 객체를 대입함
InterfaceB ib = impl;
ib.methodB();
System.out.println();
// 인터페이스C의 참조변수에 구현 객체를 대입함
// 상속받은 모든 메소드를 불러올 수 있음
InterfaceC ic = impl;
ic.methodA();
ic.methodB();
ic.methodC();
}
}
인터페이스
package ch08.sec10;
public interface Vehicle {
void run();
// 추상 메소드
}
구현(자식) 클래스
package ch08.sec10;
public class Bus implements Vehicle{
// Vehicle 인터페이스를 가져옴
// 인터페이스 내부의 메소드를 재정의
@Override
public void run() {
System.out.println("버스가 달립니다");
}
// 추가 메소드
// 승차 요금을 체크
public void checkFare() {
System.out.println("승차요금을 체크합니다.");
}
}
실행 클래스
package ch08.sec10;
public class CastingExample {
public static void main(String[] args) {
Vehicle vehicle = new Bus();
// Vehicle 인터페이스 참조변수에 Bus 객체를 생성함
// 자식(구현) 객체가 부모(인터페이스)에 대입하는 것이기 때문에 자동적으로 형 변환이 일어남
vehicle.run();
// 인터페이스 참조변수에 자식(구현) 객체를 대입했기 때문에
// Bus 객체에 있는 run 메소드가 실행됨
// vehicle.checkFare();
// 하지만 vehicle은 인터페이스 참조변수여서 인터페이스 안에 있는 내용만 참조 가능
// checkFare 메소드는 인터페이스 내부에 없는 메소드이기 때문에 불러올 수 없음
Bus bus = (Bus) vehicle;
// vehicle은 Bus 객체의 부모 개념의 Vehicle 인터페이스를 참조하는 변수이므로
// 자식(구현) 객체의 메소드를 호출하기 위해서는 해당 타입으로 변경해줘야함
// 따라서 강제 형변환을 통해 자식객체의 타입으로 변환해야함
// Vehicle 인터페이스는 Bus 객체를 참조하기 때문에 강제 형변환이 가능
bus.run();
// Bus 객체의 메소드가 실행됨
bus.checkFare();
// Bus 객체 타입으로 변환되었기 때문에 해당 객체의 메소드를 불러올 수 있음
}
}
인터페이스
package ch08.sec11.exam01;
public interface Tire {
void roll();
// 추상 메소드 선언
}
구현 클래스 (KumhoTire)
package ch08.sec11.exam01;
public class KumhoTire implements Tire{
// Tire 인터페이스를 불러옴
// Tire에서 선언한 추상메소드를 재정의해 동작을 구현함
@Override
public void roll() {
System.out.println("금호타이어가 굴러갑니다");
}
}
구현 클래스 (HankookTire)
package ch08.sec11.exam01;
public class HankookTire implements Tire{
// Tire 인터페이스를 불러옴
// Tire에서 선언한 추상메소드를 재정의해 동작을 구현함
@Override
public void roll() {
System.out.println("한국타이어가 굴러갑니다");
}
}
Car 클래스
package ch08.sec11.exam01;
public class Car {
Tire tire1 = new HankookTire();
Tire tire2 = new HankookTire();
// Tire 인터페이스 참조변수에 HankookTire 객체를 생성하여 값을 대입함
void run() {
tire1.roll();
tire2.roll();
// HankookTire 객체의 roll 메소드를 실행
}
}
실행 클래스
package ch08.sec11.exam01;
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car();
// Car 객체 생성
myCar.run();
// Car의 메소드에는 한국타이어가 설정되있음
myCar.tire1 = new KumhoTire();
myCar.tire2 = new KumhoTire();
// Car 클래스 안에 선언되어 있는 Tire 인터페이스 참조변수 필드 두개에
// 금호타이어 객체를 생성하여 타이어를 교체함
myCar.run();
// tire1, tire2 참조변수에 금호타이어 객체를 생성하여 대입하였음
// 따라서 금호타이어에서 재정의된 roll 메소드가 실행됨
}
}
인터페이스
package ch08.sec11.exam02;
public interface Vehicle {
void run();
// 추상 메소드 선언
}
Driver 클래스
package ch08.sec11.exam02;
public class Driver {
// Vehicle 인터페이스 타입의 매개변수를 1개 가지는 일반 메소드
// 구현객체가 대입될 수 있도록 매개변수를 인터페이스로 선언
void drive(Vehicle vehicle) {
// Vehicle 인터페이스의 run() 메소드를 호출함
vehicle.run();
}
}
Bus 클래스 (구현 클래스)
package ch08.sec11.exam02;
public class Bus implements Vehicle{
// Vehicle 인터페이스를 불러옴
// 인터페이스의 run 메소드를 해당 클래스에서 재정의
// 추상 메소드이기 때문에 선언하지 않으면 오류
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}
Taxi 클래스 (구현 클래스)
package ch08.sec11.exam02;
public class Taxi implements Vehicle{
// Vehicle 인터페이스를 불러옴
// 인터페이스의 run 메소드를 해당 클래스에서 재정의
// 추상 메소드이기 때문에 선언하지 않으면 오류
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
실행 클래스
package ch08.sec11.exam02;
public class DriverExam {
public static void main(String[] args) {
// Driver 객체 생성
Driver driver = new Driver();
// Bus와 Taxi 객체 생성 및 참조변수 선언
Bus bus = new Bus();
Taxi taxi = new Taxi();
// Driver 객체의 drive 메소드에 Bus와 Taxi 참조변수를 대입함
// drive 메소드의 매개변수는 Vehicle 타입인데, Bus와 Taxi 객체가
// Vehicle 인터페이스를 참조하므로 자동 형변환이 일어남
// 또한 drive 메소드 내부에 있는 run 메소드가 해당 객체에서 재정의 되어서
// Bus 객체와 Taxi 객체에 있는 run 메소드 값이 각각 나옴
driver.drive(bus);
driver.drive(taxi);
}
}
인터페이스
package ch08.sec12;
public interface Vehicle {
void run();
// 추상 메소드 선언
}
구현 클래스 Bus
package ch08.sec12;
public class Bus implements Vehicle{
// Vehicle 인터페이스를 참조
// 참조하는 인터페이스에 추상 메소드가 있기 때문에
// 해당 클래스에 추상 메소드를 모두 선언해야함
// 인터페이스에 선언된 run() 메소드 재정의
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
// 해당 클래스에서 자체적으로 만든 메소드 (승차요금 확인)
public void checkFare() {
System.out.println("승차요금을 체크합니다.");
}
}
구현 클래스 Taxi
package ch08.sec12;
public class Taxi implements Vehicle{
// Vehicle 인터페이스를 참조
// 참조하는 인터페이스에 추상 메소드가 있기 때문에
// 해당 클래스에 추상 메소드를 모두 선언해야함
// 인터페이스에 선언된 run() 메소드 재정의
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
실행 클래스
package ch08.sec12;
public class InstanceofExam {
public static void main(String[] args) {
Taxi taxi = new Taxi();
Bus bus = new Bus();
// Taxi와 Bus 객체 생성
ride(taxi);
System.out.println();
ride(bus);
}
// Vehicle 인터페이스 타입을 매개변수로 가지는 ride 메소드 생성
// 해당 클래스 실행문에서 사용을 위해 static(정적) 메소드 선언
// -> 위의 실행문이 static void main으로 시작하기 때문
// 해당 매개변수는 인터페이스를 참조하는 구현객체 타입의 형태로 대입되는데 이 과정에서 자동형변환이 일어남
public static void ride(Vehicle vehicle) {
// instanceof : 해당 타입이 자식 객체의 타입으로 변환할 수 있는지 여부를 확인하고
// 변환이 가능할 경우 변환될 타입의 변수에 객체 저장
// Bus 객체에서 Vehicle 인터페이스를 참조함으로서 강제형변환 가능
if(vehicle instanceof Bus bus) {
// Bus 객체 타입으로 강제 형변환 후 bus 참조변수에 이를 대입
// checkFare 메소드 실행
bus.checkFare();
}
// Taxi나 Bus 객체에서 재정의된 run 메소드 실행
vehicle.run();
}
}