백기선님이 과거에 진행했던 Java 스터디 8주차 스터디 입니다.
인터페이스 정의하는 방법
- 인터페이스는 일종의 추상클래스다.
- 인터페이스는 추상 클래스처럼 추상 메서드를 가진다. 그러나 추상 클래스처럼 일반 메서드를 가질 수 없다.
- 또한 인터페이스는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있다.
- 그외의 다른 어떠한 요소도 허용하지 않는다.
- 모든 메서드는 public이다.
- 인터페이스는 기본 설계도라 할 수 있다.
- 객체지향의 핵심인 다형성을 적극적으로 활용할 수 있게 해주는 요소다.
정의하는 방법은 아래와 같다.
interface 인터페이스이름{
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
인터페이스를 사용했을 때 장점 다음과 같다.
- 개발시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
인터페이스 구현하는 방법
인터페이스 구현하는 방법은 아래와 같다.
- 먼저 인터페이스를 정의한다. 아래 예시에서는 Vehicle라는 인터페이스를 만들었다.
- 이후에는 인터페이스를 구현할 클래스를 만든다. 여기서는 Bus가 인터페이스를 구현한 클래스다.
- implements 키워드를 사용해 인터페이스를 구현한다.
interface Vehicle {
}
public class Bus implements Vehicle{
}
인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
이 방식은 다형성을 이용한 것이다.
다형성이란 자손클래스의 인스턴스를 조상 클래스 타입의 참조변수로 참조할 수 있다는 것이다.
인터페이스 참조변수를 통해 구현체를 사용하는 방법을 확인해보자.
public interface Vehicle {
public void ride();
public String getName();
}
public class Car implements Vehicle {
@Override
public void ride(){
System.out.println("승용차에 탑승했습니다.");
}
@Override
public String getName(){
return "Car";
}
}
public class Bus implements Vehicle {
@Override
public void ride(){
System.out.println("버스에 탑승했습니다.");
}
@Override
public String getName(){
return "Bus";
}
}
Vehicle vehicle1 = new Car();
vehicle1.ride(); //"승용차에 탑승했습니다."
Vehicle vehicle2 = new Bus();
vehicle2.ride(); //"버스에 탑승했습니다."
implements를 이용해 인터페이스를 구현한 클래스 2가지를 만들었다.
이제 인터페이스의 추상메서드 ride()를 오버라이딩해 재정의 하고,
Vehicle 타입 참조 변수에 new 연산자를 사용해 Vehicle 인터페이스를 구현한 Bus와 Car라는 구현 클래스를 만들었다.
이제 그리고 구현 클래스 인스턴스를 할당 받은 인터페이스 참조 변수에서 오버라이딩한 메서드 ride()를 사용하면
서로 다른 출력 값이 나온다.
인터페이스 상속
인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속,
즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.
interface Attacker{
void attack();
}
interface Defender{
void defense();
}
interface Fighter extends Attacker, Movable {
}
위와 같은 코드를 작성했다.
클래스의 상속과 마찬가지로 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속받는다.
여기서는 정의된 멤버 변수는 없지만, 조상 인터페이스로부터 상속받은 두 개의 추상 메서드를 멤버, 즉 메서드로 갖게 된다.
자바는 인터페이스를 사용한 다중 상속이 가능하다고 하는데 실제를 많이 쓰이지 않는다고 한다.
인터페이스의 기본 메서드, Default Method (자바 8)
- 조상 클래스에 새로운 메서드를 추가하는 것은 별 일이 아니지만, 인터페이스의 경우네는 보통 큰일이 아니다.
- 인터페이스에 메서드를 추가한다는 것은, 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구혀한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야한다.
- 인터페이스 설계를 정말 잘 하면 문제가 없겠지만, 현실적으로 그건 어렵다. 그래서 고심 끝에,
- 디폴트 메서드(default method)라는 것이 생겼다.
- 디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다.
- 디폴트 메서드는 앞에 키워드 default를 붙이며, 추상 메서드와 달리 일반 메서드처럼 몸통 {}이 있어야 한다.
- 디폴트 메서드 역시 public이며, 생략 가능하다.
interface MyInterface {
void method(); //추상 클래스
default void newMethod2(){ //오버라이딩 하도 되지 않는 디폴트 메서드
System.out.println("called method()2");
};
}
- 대신, 새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생하는데 이를 해결하는 규칙은 다음과 같다.
- 사실 결론은 필요한 쪽의 메서드와 같은 내용으로 오버라이딩하면 된다.
- 여러 인터페이스의 디폴트 메서드 간의 충돌 : 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
- 디폴트 메서드와 조상 클래스의 메서드 간의 충돌 : 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
인터페이스의 static 메서드 (자바 8)
- 자바 8부터 인스턴스와 관계가 없는 독립적인 static 메서드를 인터페이스에서도 사용할 수 있게 되었다.
- 인터페이스의 static 메서드도 접근 제어자가 항상 public이며, 생략할 수 있다.
public interface Human {
void eat();
default void run() {
System.out.println("Run!!!");
}
static void sleep() {
System.out.println("Zzzzz");
}
}
Human.sleep()//이렇게 사용
인터페이스의 private 메서드 자바 9
- 인터페이스의 private 메서드는 말 그대로 인터페이스 내부에서만 사용할 수 있는 private한 메서드다.
- private 메소드의 특징은 다음과 같다.
- 메서드 바디가 있고, 추상 메서드가 아니다.
- static 이거나 non-static 일 수 있다.
- 구현 클래스와 인터페이스가 상속되지 않는다.
- private는 private, abstract, default 또는 static 메소드를 호출 할 수 있다.
- private static은 static 및 static private 메소드만 호출 할 수 있다.
public interface MyInterface {
private static int staticMethod() {
return 42;
}
private int nonStaticMethod() {
return 0;
}
}
이상으로 포스팅을 마칩니다. 감사합니다!
참고자료
자바의 정석(저자 : 남궁성)
댓글