다형성
객체지향 츠로그래밍의 대표적인 특징 캡슐화, 상속, 다형성이 있다.
추상클래스
동물과 같이 부모 클래스는 제공하지만, 실제 생성되면 안되는 클래스를 추상클래스라 한다.
- 직접 인스턴스를 생성할 수 없는 제약이 있다.
- 부모 클래스를 상속 받는 자식 클래스가 반드시 오버라이딩 해야 하는 메서드를 부모 클래스에 정의할 수 있다. 즉 상속받은 하위 클래스에서 구체적인 구현을 제공하여 인스턴스화 한다.
public abstract class ElectronicDevice {
abstract void doSomething();
public void turnOn() {
System.out.println("전원 켬");
}
public void turnOff() {
System.out.println("전원 끔");
}
}
public class Phone extends ElectronicDevice{
@Override
void doSomething() {
System.out.println("전화, 검색 ...");
}
}
public class Tv extends ElectronicDevice{
@Override
void doSomething() {
System.out.println("Netflix, Youtube 시청 ...");
}
}
public class AbstractMain1 {
public static void main(String[] args) {
ElectronicDevice[] devices = {new Phone(), new Tv()};
for (ElectronicDevice electronicDevice : devices) {
print(electronicDevice);
}
}
private static void print(ElectronicDevice electronicDevice) {
electronicDevice.turnOn();
electronicDevice.doSomething();
electronicDevice.turnOff();
}
}
- 추상 메서드가 하나라도 존재한다면 추상 클래스로 선언해야 함.
- 추상 클래스는 공통 동작을 정의하면서, 각기 다른 구현이 필요한 하위 클래스에서 구
인터페이스
- 인터페이스와 멤버변수
- 인터페이스에서 멤버변수는 public, static, final이 모두 포함되어 있다. final 변수의 값을 한번 설정하면 수정할 수 없다.
- 인터페이스(순수 추상클래스)와 동일하게 new로 생성할 수 없다.
- 클래스, 추상 클래스, 인터페이스는 프로그램 코드, 메모리 구조상 모두 동일하다. 인터페이스 작성 시에더 .java에 인터페이스를 정의함.
상속 vs. 구현
상속은 부모의 기능을 물려 받는 것이 목적, 반면에 인터페이스는 모든 메서드가 추상메서드. 따라서 물려받는 기능이 없고 인터페이스에 정의한 모든 메섣를 자식이 오버라이딩하여 구현해야 함. 인터페이스는 단순히 설계도이고 이 설계도가 어떻게 동작하는지는 하위 클래스에 있다.
인터페이스를 사용하는 이유
- 제약을 준다.
- 인터페이스를 구현하는 곳에서 인터페이스의 메서드를 반드시 구현하라는 규제를 주는것과 비슷한 효과를 준다.
- 다중 구현
- 상속은 부모 하나만 지정할 수 있지만 인터페이스는 부모를 여러명 두는 다중 구현(상속)이 가능
// 컨트롤러 인터페이스
public interface ControllerInterface {
void turnOn();
void turnOff();
void doSomething();
default void doSome() {
System.out.println("ControllerInterface.doSome");
}
}
public class RemoteController implements ControllerInterface{
@Override
public void turnOn() {
System.out.println("tv 전원을 켠다.");
}
@Override
public void turnOff() {
System.out.println("tv 전원을 끈다.");
}
@Override
public void doSomething() {
System.out.println("채널을 돌린다.");
}
@Override
public void doSome() {
ControllerInterface.super.doSome();
}
}
public class CarController implements ControllerInterface{
@Override
public void turnOn() {
System.out.println("시동을 건다.");
}
@Override
public void turnOff() {
System.out.println("시동을 끈다.");
}
@Override
public void doSomething() {
System.out.println("차가 주행한다.");
}
@Override
public void doSome() {
ControllerInterface.super.doSome();
}
}
public class ControllerMain {
public static void main(String[] args) {
ControllerInterface[] interfaces = {new CarController(), new RemoteController()};
for (ControllerInterface anInterface : interfaces) {
control(anInterface);
}
}
private static void control(ControllerInterface anInterface) {
anInterface.turnOn();
anInterface.doSomething();
anInterface.turnOff();
}
}