상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술이다.
메소드 호출 시 어떤 구현 객체를 매개값으로 주느냐에 따라서 메소드의 실행 결과는 다르게 나온다.
예를 들면, 인터페이스 A의 구현 클래스 B와 C가 있을 때, B클래스를 통해서 원하는 결과가 나오지 않으면 간단하게 C클래스로 바꿔서 실행 할 수 있다.
그것을 유용하게 바꾸기 위해 인터페이스는 메소드의 매개 변수로 많이 사용된다. 매개 변수를 인터페이스 타입으로 선언하면 메소드 호출 시 매개 값으로 다양한 구현 객체를 주어서 다양한 실행 결과가 나오게 할 수 있다.
public interface A {
// ....
}
public class B implements A {
// ....
}
public class C implements A {
// ....
}
public class Main {
public void methodD(A a){
// ....
}
}
매개 변수 a의 값으로 B 객체 또는 C 객체를 줄 수 있다. 이 때 B 객체 또는 C 객체를 넣으면 객체가 자동 타입 변환이 일어난다.
필드의 다형성
HankookTire와 KumhoTire 에서 공통적인 Tire 부분을 추출해서 인터페이스로 만들어서 필드에 다형성을 적용해볼 수 있다.
// 인터페이스 Tire.java
pulbic interface Tire {
public void roll(); // 추상 메소드, 반드시 오버라이딩 해야한다.
}
// 구현 클래스 HankookTire.java
public class HankookTire implements Tire {
@Override
public void roll() {
System.out.println("한국타이어가 굴러갑니다.");
}
}
// 구현 클래스 KumhoTire.java
public class KumhoTire implements Tire {
@Override
public void roll() {
System.out.println("금호타이어가 굴러갑니다.");
}
}
// 구현 객체를 적용하는 Car.java
public class Car {
Tire frontLeftTire = new HankookTire();
Tire frontRightTire = new HankookTire();
Tire backLeftTire = new HankookTire();
Tire backRightTire = new HankookTire();
public void run() {
frontLeftTire.roll();
frontRightTire.roll();
backLeftTire.roll();
backRightTire.roll();
}
}
// 실행 클래스 Main.java
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.run();
car.frontLeftTire = new KumhoTire();
car.frontRightTire = new KumhoTire();
car.run();
}
}
Car 객체의 필드를 다양하게 해서 run() 메소드를 실행하면 roll() 의 결과가 다르게 나타난다.
매개 변수의 다형성
상속과 비슷하게 매개변수에 인터페이스 타입을 선언하고 호출 할 때는 구현 타입으로 호출하는 방법이다.
// 인터페이스를 적용하는 Driver.java
public class Driver {
public void drive(Vehicle vehicle) { // 인터페이스 타입을 매개변수로 선언해서 구현 객체를 받을 수 있도록 한다.
vehicle.run(); // 받은 구현 객체의 run() 메소드를 실행한다.
} // 인터페이스의 run() 추상 메소드를 구현 클래스에서 구현해야 한다.
}
// 인터페이스 Vehicle.java
public interface Vehicle {
public void run(); // 추상 메소드
}
// 구현 클래스 Bus.java
public class Bus {
@Override
public void drive() {
System.out.println("버스가 달립니다");
}
}
// 구현 클래스 Taxi.java
public class Taxi {
@Override
public void drive() {
System.out.println("택시가 달립니다");
}
}
// 실행하는 Main.java
public class Main {
public static void main(String[] args) {
Driver driver = new Driver();
Bus bus = new Bus();
Taxi taxi = new Taxi();
driver.drive(bus); // 다양한 구현 객체를 매개변수에 넣어서 구현 클래스의 구현된 메소드를 실행한다.
driver.drive(taxi);
}
}
매개변수를 다양하게 함으로써 실행결과를 다르게 할 수 있다.
강제 타입 변환
참조 객체가 인터페이스 타입으로 자동 타입 변환이 되면 인터페이스에 있는 메소드만 사용할 수 있게 된다. 근데 경우에 따라서 바뀐 타입을 다시 클래스 타입으로 바꿔서 클래스에 있는 필드와 메소드를 사용해야 할 때가 있다. 이 때 강제 타입 변환을 사용하는 것이다.
// 인터페이스 Vehicle.java
public class Vehicle {
public void run();
}
// 구현 클래스 Bus.java
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
public void checkFare() {
System.out.prinlnt("승차 요금 체크");
}
}
// 실행 클래스 Main.java
public class Main {
public static void main(String[] args) {
Vehicle vehicle = new Bus(); // 자동 타입 변환으로 인해 인터페이스 메소드밖에 사용 불가.
vehicle.run();
Bus bus = (Bus) vehicle; // 강제 타입 변화
bus.run();
bus.checkFave; // 구현 객체의 메소드 사용 가능.
}
}