리셋 되지 말자

상속과 인터페이스 본문

Java(폐지)/Java 공부

상속과 인터페이스

kyeongjun-dev 2020. 7. 16. 15:24

자바의 다중 상속

  • 자바는 다중 상속을 지원하지 않는다. 왜?
  • C++를 계승/발전/단순화하면서 다중 상속을 빼버린 이유는 다음과 같다.

  • 위와 같이 사람과 물고기를 상속받은 인어라는 클래스에서 '수영하다'라는 메서드가 실행되면 사람 클래스의 수영메서드를 수행할지, 물고기 클래스의 수영메서드를 수행할지 정하기가 애매하다. 이와 같은 문제를 '다중 상속의 다이아몬드 문제'라고 한다.
  • 결국 다중상속은 득실 관계에서 실이 더 많았기에 자바와 C#에서는 다중 상속을 포기했다.
  • 대신 자바에서는 C++에는 없는 '인터페이스'를 도입해 다중 상속의 득은 취하고 실은 과감히 버렸다.

상속과 인터페이스

  • 상속 관계가 is a kind of 관계라고 앞 절에서 언급하였다. 해석과 예제를 복습하면 아래와 같다.
    -> 상속 관계 : 하위 클래스 is a kind of 상위 클래스
    -> 해석 : 하위 클래스는 상위 클래스의 한 분류이다.
    -> 예제 : 고래는 동물의 한 분류다.

  • 인터페이스
    -> 인터페이스 : 구현 클래스 is able to 인터페이스
    -> 해석 : 구현 클래스는 인터페이스를 할 수 있다
    -> 예제 : 고래는 헤엄칠 수 있다

  • 인터페이스를 적용한 상속도(분류도)

  • 인터페이스는 be able to, 즉 '무엇을 할 수 있는' 이라는 표현 형태로 만드는 것이 좋다. 자바 API에서도 이러한 형식의 인터페이스를 많이 볼 수 있다. 아래는 몇 가지 예이다.
    -> Serializable 인터페이스 : 직렬화할 수 있는
    -> Cloneable 인터페이스 : 복제할 수 있는
    -> Comparable 인터페이스 : 비교할 수 있는
    -> Runnable 인터페이스 : 실행할 수 있는

  • 상위 클래스는 하위 클래스에게 특성(속성과 메서드)을 상속해 주고, 인터페이스는 클래스가 '무엇을 할 수 있다'라고 하는 기능을 구현하도록 '강제'하게 된다. 여기서 아래의 두 퀴즈를 풀어보자
    -> 상위 클래스는 하위 클래스에게 물려줄 특성이 많을수록 좋을까? 적을수록 좋을까?
    -> 인터페이스는 구현을 강제할 메서드가 많을수록 좋을까? 적을수록 좋을까?

  • 상위 클래스는 물려줄 특성이 풍성할수록 좋고, 인터페이스는 구현을 강제할 메서드의 개수가 적을수록 좋다.
    -> 상위 클래스가 풍성할수록 좋은 이유는 LSP(리스코프 치환 원칙)에 따른 이유이다.
    -> 인터페이스에 메서드가 적을수록 좋은 이유는 ISP(인터페이스 분할 원칙)에 따른 이유이다.

인터페이스 사용 예제

  • 동물
package ingeritance02;

public class 동물 {
    String myClass;

    동물(){
        myClass = "동물";
    }

    void showMe() {
        System.out.println(myClass);
    }
}
  • 날수있는
package ingeritance02;

public interface 날수있는 {
    void fly();
}
  • 헤엄칠수있는
package ingeritance02;

public interface 헤엄칠수있는 {
    void swim();
}
  • 포유류
package ingeritance02;

public class 포유류 extends 동물{
    포유류(){
        myClass="포유류";
    }
}
  • 조류
package ingeritance02;

public class 조류 extends 동물{
    조류(){
        myClass = "조류";
    }
}
  • 고래
package ingeritance02;

public class 고래 extends 포유류 implements 헤엄칠수있는{
    고래(){
        myClass="고래";
    }

    @Override
    public void swim() {
        System.out.println(myClass + " 수영 중. 어푸 어푸");
    }
}
  • 박쥐
package ingeritance02;

public class 박쥐 extends 포유류 implements 날수있는{
    박쥐(){
        myClass="박쥐";
    }

    @Override
    public void fly() {
        System.out.println(myClass + "나는 중. 슈웅 슈웅");
    }
}
  • 참새
package ingeritance02;

public class 참새 extends 조류 implements 날수있는{
    참새(){
        myClass="참새";
    }

    @Override
    public void fly() {
        System.out.println(myClass + "나는 중. 푸슝푸슝");
    }
}
  • 펭귄
package ingeritance02;

public class 펭귄 extends 조류 implements 헤엄칠수있는{
    펭귄(){
        myClass = "펭귄";
    }

    @Override
    public void swim() {
        System.out.println(myClass + "수영 중. 어푸 어푸");
    }
}
  • main
package ingeritance02;

public class Main01 {

    public static void main(String[] args) {
        날수있는 날라리1 = new 박쥐();
        날라리1.fly();

        날수있는 날라리2 = new 참새();
        날라리2.fly();

        헤엄칠수있는[] 맥주병들 = new 헤엄칠수있는[2];
        맥주병들[0] = new 고래();
        맥주병들[1] = new 펭귄();

        for(헤엄칠수있는 맥주병 : 맥주병들) {
            맥주병.swim();
        }

    }

}
  • 결과

  • 인터페이스는 이를 구혀한 클래스의 조상이라 할 수 있으므로, 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있다. 인터페이스 타입으로 형변환도 가능하다.
    -> ex) 날수있는 인터페이스의 fly()를 구현한 박쥐 클래스의 인스턴스를 날수있는 인터페이스 타입의 객체 참조 변수 날라리1이 박쥐클래스의 인스터스를 참조한다. 날수있는 날라리1 = new 박쥐();
  • 이해하기가 어려워 다른 분의 블로그를 참조하여 이해함(https://devbox.tistory.com/entry/Java-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%EB%8B%A4%ED%98%95%EC%84%B1)

상속과 UML 표기법

  • 두 클래스 간의 상속을 표현하기 위해 하위 클래스에서 상위 클래스 쪽으로 화살표를 그린다.
  • 클래스가 인터페이스를 구현한 경우에는 가운데 그림과 같이 그린다.
  • 인터페이스 구현에 대해 약식으로 표현하기도 하는데, 세 번째 그림이 약식 포현이다.

'Java(폐지) > Java 공부' 카테고리의 다른 글

다형성: 사용편의성  (0) 2020.07.17
상속과 T 메모리  (0) 2020.07.16
상속  (0) 2020.07.16
5일차-클래스 멤버 vs 객체 멤버 = static 멤버 vs 인스턴스 멤버  (0) 2020.07.15
4일차 - 자바와 객체 지향  (0) 2020.07.14
Comments