인터페이스(interface)

정순동·2023년 12월 8일
0

자바기초

목록 보기
36/89

인터페이스

인터페이스란? 추상 클래스처럼 추상 메서드를 갖지만 추상 클래스보다 추상화 정도가 높아서 일반 메서드(구현부가 구현된)또는 멤버변수(int x;등)를 구성원으로 가질 수 없다.
오직 추상 메서드와 상수만을 멤버로 가질 수 있다.
인터페이스도 추상 클래스처럼 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움 줄 목적으로 작성한다.

인터페이스를 작성하는 방법은 클래스와 비슷하다. 추상 클래스처럼 앞에 무언가를 붙힐 필요는 없고 그저 class를 interface로 바꾸어 주면된다.

	interface InterfaceName {
    	public static final 타입 상수이름 = 값;
        public abstract 메서드이름(매개변수목록);
    }

일반적인 클래스와 달리 인터페이스의 멤버들은 다음과 같은 제약사항이 존재한다

  • 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.
  • 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.
    (단, static메서드와 디폴트 메서드는 예외)
	interface PlayingCard {
    	public static final int S = 4;
        final int DIAMOND = 3;	// public static final int DIAMOND = 3;
        static int HEART = 2;	// public static final int HEART = 2;
        int CLOVER = 1; 		// public static final int CLOVER = 1;
        
        public abstract String getCardNumber();
        String getCarKind();	// public abstract String getCarKind();
    }

그저 타입과 상수이름, 반환타입과 메서드명만 적어 주어도 컴파일러에서 자동으로 public static final을 앞에 붙혀주기 때문에 생략이 가능하다.

인터페이스의 장점

인터페이스의 장점

  • 개발시간을 단축시킬 수 있다.
  • 표준화가 가능하다.
  • 서로 관계없는 클래스들에게 관계를 맺어 줄 수있다.
  • 독립적인 프로그래밍이 가능하다.

인터페이스의 상속

인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러개의 인터페이스로부터 상속을 받는 것이 가능하다.

	interface Movable {
    	// 지정된 위치(x, y)로 이동하는 기능의 메서드
        void move(int x, int y);
    }
    
    interface Attackable {
    	// 지정된 대상(u)을 공격하는 기능의 메서드
        void attack(Unit u);
    }
    
    interface Fightable extends Movable, Attacable { }

클래스의 상속과 마찬가지로 자손 인터페이스(Fightable)은 조상 인터페이스에 정의된 멤버를 모두 상속받는다.

인터페이스의 구현

인터페이스도 추상 클래스처럼 그 자체로는 인스턴스 생성이 불가능하다. 인터페이스도 자신에 정의된 추상메서드를 구현할 클래스를 작성해야 하는데, 키워드만 'extends'에서 'implements'로 바뀐다.

	class 클래스 이름 implements 인터페이스이름 { }
    
    class Fighter implements Fightable {
    	public void move(int x, int y) { //생략 }
        public void attack(Unit u) { //생략 }
    }

만일 구현하는 인터페이스의 메서드 중 일부만 구현한다면, abstract를 붙여서 추상 클래스로 선언해야 한다.

	abstract class Fighter implements Fightable {
    	public void move(int x, int y) { //생략 }
        // attack()메서드를 구현하지 않음.
    }

다음과 같이 상속과 구현을 동시에 할 수 있다.

	class Fighter extends Unit implements Figtable {
    	public void move(int x, int y) { //생략 }
        public void attac(Unit u) { //생략 }
    }

인터페이스를 이용한 다형성

상속을 이용한 클래스의 다형성에서 자손클래스의 인스턴스를 조상타입의 참조변수로 참조하는 것이 가능했었다. 인터페이스 역시 이를 구현한 클래스의 입장에서 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다.

	Fightable f = (Fightable)new Fighter();
    
    Fightable f = new Fighter();
    
    // 따라서 아래와 같이 메서드의 매개변수타입으로 인터페이스도 가능하다.
    void attack(Fightable f) {
    	//...
    }

인터페이스 타입의 매개변수가 갖는 의미는 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 한다는 뜻이다.

	class Fighter extends Unit implements Fightable {
    	public void move(int x, int y) { //생략 }
        public void attack(Fightable f) { //생략 }
    }
    
    Fightable method() {
    	Fighter f = new Fighter();
        return f;
    }

위의 코드에서 볼 수 있듯, Fightable을 반환하는 메서드에 그 구현 클래스의 인스턴스를 반환하는것도 가능하다.
리턴 타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
위 코드에서는 Fightable 인터페이스를 구현한 클래스들 중 Fighter클래스의 인스턴스가 반환된다는 것을 의미한다.

디폴드 메서드와 static 메서드

원래는 인터페이스에 abstract 메서드만 선언할 수 있었지만 java8부터는 디폴트 메서드와 static메서드도 추가할 수 있게 되었다. 인터페이스의 경우 추상화의 끝판왕이라 볼 수 있기때문에 하나의 인터페이스에 메서드 한개가 추가될 경우 엄청나게 많은 클래스를 수정해야 할 수도 있다. 그래서 JDK 설계자들은 디폴트 메서드(default method)라는 것을 고안해내었다. 디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로, 새로 추가되어도 해당 클래스에서 구현할 필요가 없다.

	interface MyInterface {
   		void method();
    }
    //에서
    interface MyInterface {
    	void method();
        default void newMethod() {}
    }

위의 인터페이스에서 아래와같이 default메서드로 newMethod()를 선언해 준다면 이 인터페이스를 구현했던 모든 클래스에서 해당 newMethod를 구현하지 않아도 된다. 조상클래스에서 새로운 메서드를 만든것과 동일하다.
대신, 디폴트 메서드가 구현해 놓았떤 메서드와 이름이 중복되어 충돌하는 경우가 발생할 수 있는데, 다음과 같은 규칙으로 해결할 수 있다.

  1. 여러 인터페이스의 디폴트 메서드 간의 충돌
    • 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
  2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
    • 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

0개의 댓글