자식 클래스가 여러 부모 클래스를 상속받을수 있다면, 다양한 동작을 수행할 수 있다는 장점을 가지게 될 것입니다. 하지만 클래스로 다중 상속을 할 경우 모호성 등 여러가지 문제가 발생할 수 있어 자바에서는 클래스를 통한 다중 상속은 지원하지 않는다.
하지만 자바에선 인터페이스를 통해 다중 상속을 지원한다.
인터페이스란 다른 클래스를 작성할 때 기본이 되는 틀을 제공하면서, 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스를 의미한다.
자바에서 추상 클래스는 추상 메소드뿐만 아니라 생성자, 필드, 일반 메소드도 포함할 수 있다. 하지만 인터페이스는 오로지 메소드와 상수만을 포함할 수 있다.
인터페이스 선언
인터페이스를 선언할 때에는 접근 제어자와 함께interface 키워드를 사용하면 된다.
EX.
접근제어자 interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
...
public abstract 메소드이름(매개변수목록);
...
}
단, 클래스와는 달리 인터페이스의 모든 필드는 public static final이어야 하며, 모든 메소드는 public abstract이어야 한다.
(제어자는 생략 가능, 컴파일 시 자동 추가)
인터페이스 구현
인터페이스는 추상 클래스와 마찬가지로 자신이 직접 인스턴스를 생성할 수는 없다.
따라서 인터페이스가 포함하고 있는 추상 메소드를 구현해 줄 클래스를 작성해야만 한다.
EX.
class 클래스이름 implements 인터페이스이름 { ... }
만약 모든 추상 메소드를 구현하지 않는다면, abstract 키워드를 사용하여 추상 클래스로 선언해야 한다.
++
자바에서는 다음과 같이 상속과 구현을 동시에 가능
class 클래스이름 extend 상위클래스이름 implements 인터페이스이름 { ... }
EX.다중 상속
interface Animal { public abstract void cry(); }
interface Pet { public abstract void play(); }
class Cat implements Animal, Pet {
public void cry() {
System.out.println("냐옹냐옹!");
}
public void play() {
System.out.println("쥐 잡기 놀이하자~!");
}
}
class Dog implements Animal, Pet {
public void cry() {
System.out.println("멍멍!");
}
public void play() {
System.out.println("산책가자~!");
}
}
public class Polymorphism04 {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
c.cry();
c.play();
d.cry();
d.play();
}
}
클래스를 이용한 다중 상속의 문제점
같은 cry() 가지고 있는 클래스가 여러개 있는 경우 출력시 어느 메소드인지 구분할 수 없는 모호성을 지니게 되어 자바에서는 클래스를 이용한 다중 상속을 지원하지 않는다.
class Animal {
public void cry() {
System.out.println("짖기!");
}
}
class Cat extends Animal {
public void cry() {
System.out.println("냐옹냐옹!");
}
}
class Dog extends Animal {
public void cry() {
System.out.println("멍멍!");
}
}
① class MyPet extends Cat, Dog {}
public class Polymorphism {
public static void main(String[] args) {
MyPet p = new MyPet();
② p.cry();
}
}
하지만 인터페이스를 이용하여 다중 상속을 하게되면 위와 같은 메소드 호출의 모호성을 방지할 수 있다.
인터페이스의 장점
인터페이스 타입으로 객체를 생성할 수 있으며 해당 객체에 구현 클래스로 인스턴스화 할 수 있다.
인터페이스 타입으로 선언한 객체는 구현 클래스 내에서 생성한 메서드, 필드를 사용할 수 없다.
인터페이스의 default 메소드
인터페이스가 dafault 키워드로 선언되면 메소드가 구현될 수 있다. 또한 이를 구현하는 클래는 dafault 메소드를 오버라이딩 할 수 있다. Java 8 이후부터 default 메소드를 사용하면 메서드 구현부를 가질 수 있다.
EX.
public interface calculator{
dafault int exec(int i, int j){
retrun i + j;
}
}
public class mycal{
public static void main(string[] atgs){
claculator cal = new my mycal();
system.out.println(value);
}
}
인터페이스가 변경 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다. 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 하였다.
static 메소드
Java 8 부터 생겨난 static 메소드는 인터페이스를 이용하여 간단한 기능을 가지는 유탈리티 성 인터페이스를 만들 수 있다.
- 상속 불가능.
- 인터페이스의 상수와 같은 형식으로 쓰인다.
- interface이름.static메소드이름 으로 사용.
public interface Calculator {
public int plus(int i, int j);
public int multiple(int i, int j);
default int exec(int i, int j){
return i + j;
}
public static int exec2(int i, int j){ //static 메소드
return i * j;
}
}
//인터페이스에서 정의한 static메소드는 반드시 인터페이스명.메소드 형식으로 호출해야한다.
public class MyCalculatorExam {
public static void main(String[] args){
Calculator cal = new MyCalculator();
int value = cal.exec(5, 10);
System.out.println(value);
int value2 = Calculator.exec2(5, 10); //static메소드 호출
System.out.println(value2);
}
}
인터페이스에 static 메소드를 선언함으로써, 인터페이스를 이용하여 간단한 기능을 가지는 유틸리티성 인터페이스를 만들 수 있다.
인터페이스의 메소드는 public이다. java9 부터는 private를 사용함으로써 외부에 공개하지 않게 하며 코드의 중복을 피하고 interface에 대한 캡슐화를 유지할 수 있게 한다.
private : private, abstract, default, static 메서드 호출 가능
private static : static, private static 메서드만 호출 가능
래퍼런스
http://www.tcpschool.com/java/java_polymorphism_interface
https://youn12.tistory.com/31
https://school.programmers.co.kr/learn/courses/5/lessons/241