interface

6 분 소요

Interface

  • 객체 사용 방법을 정의한 타입
  • 개발 코드와 객체가 서로 통신하는 접점 역할

    개발 코드가 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출, 그렇기 때문에 개발 코드는 객체의 내부 구조를 알 필요가 없이 인터페이스의 메소드만 알고있으면 됨.

개발코드가 직접 객체의 메소드를 호출하면 간단하지만, 왜 중간에 인터페이스를 두는지 의문점이 생김 그 이유는 개발코드를 수정하지 않고, 사용하는 객체를 변경할 수 있도록 하기 위해서 임.

  • 인터페이스는 하나의 객체가 아닌 여러 객체들과 사용이 가능하므로, 사용 객체에 따라 실행 내용과 리턴값이 다름 (코드 변경없이 다양화 가능하다는 장점있음.)

인터페이스 선언

접근제한자 interface 인터페이스명 {...} 
  • 영어 대소문자를 구분 하며, 첫문자를 대문자로 하고 나머지는 소문자로 작성하는것이 관례
  • 인터페이스는 상수와 메소드만을 구성 멤버로 가짐.
    interface 인터페이스명{
       //상수
       타입 상수명 = ;
       //추상 메소드
       타입 메소드명(매개변수, ...);
       //디폴트 메소드
       default 타입 메소드명(매개변수){...}
       //정적 메소드
       static 타입 메소드명(매개변수){...}
    }
    

상수 필드(Constant Field)

  • 인터페이스는 객체 사용 설명서이므로 런타임 시 데이터를 저장할 수 있는 필드 선언 불가함.
  • 상수 필드는 선언 가능, 상수는 인터페이스에 고정된 값으로 런타임 시 데이터를 바꿀수 없음
  • 상수 선언 시 반드시 초기값 대입 해야함.

추상 메소드(Abstract Method)

  • 추상 메소드는 객체가 가지고있는 메소드를 설명한 것, 호출 시 어떤 매개값이 필요하고, 리턴 타입이 무엇인지만 알려줌
  • 실제 실행부는 객체(구현 객체) 가 가지고있음.

디폴트 메소드(Default Method)

  • 디폴트 메소드는 인터페이스에 선언, 사실은 객체(구현 객체)가 가지고 있는 인스턴스 메소드라고 생각해야 함.

정적 메소드 (Static Method)

  • 디폴트 메소드와는 달리 객체가 없어도 인터페이스만으로 호출이 가능

상수 필드 선언

public static final 타입 상수명 = ; 
  • 상수명은 대문자로 작성하되, 서로 다른 단어로 구성되어 있을 경우에는 언더바(_)로 연결하는것이 관례
  • 인터페이스 상수는 static{} 블록으로 초기화할 수 없기 때문에선언과 동시에 초기값을 지정

추상 메소드 선언

  • 인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행하므로 실행 블록이 필요없는 추상메소드로 선언
    • 추상메소드는 리턴타입, 메소드명, 매개변수만 기술되고 중괄호 {} 를 붙이지 않는 메소드
  • 인터페이스에 선언된 추상 메소드는 모두 public abstract 특성을 갖기 때문에 생략 되더라도 자동적으로 컴파일 과정에서 생성함.

디폴트 메소드 선언

  • 클래스의 인스턴스 메소드와 동일한 형태, default 키워드가 리턴 타입 앞에 붙음.
  • 디폴트 메소드는 public 특성을 갖기때문에 public을 생략하더라도, 자동적으로 컴파일 과정에서 붙게 됨.
    [public] default 리턴타입 메소드명(매개변수,...){...}
    

정적 메소드 선언

  • 클래스의 정적 메소드와 동일한 형태, 적적 메소드는 public 특성을 갖기 때문에 public 을 생략 하더라도, 자동적으로 컴파일 과정에서 붙게 됨.
    [public] static 리턴타입 메소드명(매개변수){...}
    

인터페이스 구현

  • 개발코드가 인터페이스 메소드 호출 시 인터페이스는 객체의 메소드를 호출함.
  • 객체는 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 함.
  • 이러한 객체를 인터페이스의 구현(implement) 객체 라고 하고, 구현 객체를 생성하는 클래스를 구현 클래스라고 함.

구현 클래스

  • 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 클래스 선언부에 implements 키워드를 추가하고 인터페이스명을 명시
public class 구현클래스명 implements 인터페이스명{
    //인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
  • 구현 클래스에서 인터페이스의 추상 메소드들에 대한 실체 메소드를 작성할 때 주의할점은 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public 보다 더 낮은 접근 제한으로 작성 불가
  • 인터페이스에 선언된 추상메소드에 대응하는 실체 메소드를 구현 클래스가 작성하지 않으면 구현 클래스는 자동적으로 추상클래스가 됨. 그렇기 때문에 클래스 선언부에 abstract 키워드를 추가해야함.
public abstract class Television implements RemoteControl{
    public void turnOn(){...}
    public void turnOff(){...} // setVolume() 실체 메소드가 없고, 일부만 구현
}
  • 인터페이스 변수는 참조 타입이기때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장
  • 구현객체를 인터페이스 변수에 대입해서 사용 ```java 인터페이스 변수; 변수 = 구현객체;

인터페이스 변수 = 구현객체;


## 익명 구현 객체
```java
인터페이스 변수 = new 인터페이스(){
    //인터페이스에 선언된 추상메소드의 실체 메소드 선언
}; // 하나의 실행문이므로 끝에는 세미콜론(;)을 반드시 붙여야 함.
  • UI 프로그래밍, 임시 작업 스레드를 만들기 위해 익명 구현 객체를 많이 활용
  • 하나의 실행문 이므로 끝에는 세미콜론’;’ 을 반드시 붙여야 함.

  • 인터페이스 (){}는 인터페이스를 구현해서 중괄호 {}와 같이 클래스를 선언하라는 뜻, new 연산자는 이렇게 선언 된 클래스를 객체로 생성함.
  • 중괄호 {}에는 인터페이스에 선언된 모든 추상 메소드들의 실체 메소드를 작성해야 함

    필드와 메소드를 선언할 수 있지만, 익명 객체 안에서만 사용할 수 있고 인터페이스 변수로 접근할 수 없음.

다중 인터페이스 구현 클래스

public class 구현클래스명 implements 인터페이스A, 인터페이스B{
    // 인터페이스 A에 선언된 추상 메소드의 실체 메소드 선언
    // 인터페이스 B에 선언된 추상 메소드의 실체 메소드 선언
}
  • 인터페이스 A와 인터페이스 B가 객체의 메소드를 호출할 수 있으려면 객체는 이 두 인터페이스를 모두 구현해야함.
  • 다중 인터페이스를 구현할 경우, 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성 (만약 하나라도 없으면 추상 클래스로 선언해야 함)

관련코드

인터페이스 사용

  • 인터페이스 변수는 참조 타입이기때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장
인터페이스 변수;
변수 = 구현 객체;
---------------------
인터페이스 변수 = 구현 객체;

public class Myclass {
    RemoteControl rc = new Television();

    Myclass(RemoteControl rc){ //Myclass mc = new Myclass(new Television());
        this.rc = rc;
    }

    void methodA(){
        RemoteControl rc = new Audio();
    }
    void methodB(RemoteControl rc){...} // mc.methodB(new Audio());
}

추상 메소드 사용

  • 구현 객체가 인터페이스 타입에 대입되면 인터페이스에 선언된 추상 메소드를 개발코드에서 호출할 수 있게됨.
	RemoteControl rc = null; //인터페이스 변수 선언
		
	rc = new Te(); // Te 객체를 인터페이스타입에 대입
	rc.turnOn();
	rc.turnOff();

디폴트 메소드 사용

RemoteControl rc = new Te();
rc.setMute(true);
  • 디폴트 메소드는 인터페이스에 선언되지만, 인터페이스에서 바로 사용불가함. 구현 객체가 있어야 사용 가능함
  • 구현 객체는 디폴트 메소드를 재정의(오버라이딩) 해서 자신에게 맞게 수정하면 디폴트 메소드가 호출될때 자신을 재정의한 메소드가 호출됨.

정적 메소드 사용

  • 인터페이스의 정적 메소드(static method) 는 인터페이스로 바로 호출이 가능
    RemoteControl.changeBattery();
    

타입 변환과 다형성

  • 프로그램 소스 코드는 변함이 없는데, 구현 객체를 교체함으로써 프로그램의 실행결과가 달라짐
    • 인터페이스의 다형성
  • 상속은 같은 종류의 하위클래스를 만드는 기술, 인터페이스는 사용방법이 동일한 클래스를 만드는 기술
  • 인터페이스 타입으로 매개변수를 선언하면 메소드 호출 시 매개값으로 여러가지 종류의 구현 객체를 줄 수 있기때문에 메소드 실행결과가 다양하게 나옴
    • 매개변수의 다형성

자동타입 변환(Promotion)

인터페이스 변수 = 구현객체; 
  • 구현 객체가 인터페이스 타입으로 변환되는것은 자동타입변환에 해당함.

    프로그램 실행 중 자동적으로 타입 변환이 일어나는것

  • 필드와 매개변수의 타입을 인터페이스로 선언하면 다양한 구현 객체를 대입해서 실행결과를 다양하게 만들 수 있음.

인터페이스 배열로 구현 객체 관리

Tire[] tires = {
    new HankookTire();
    new HankookTire();
    new HankookTire();
    new HankookTire();
}
  • 4개의 필드를 인터페이스로 각각 선언 할수도 있지만 위와같이 인터페이스 배열로 관리할 수도 있음.

매개변수의 다형성

  • 자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생함.
  • 매개변수를 인터페이스 타입으로 선언하고 호출할때는 구현 객체를 대입한다.
public class Driver{
    public void drive(Vehicle vehicle) {
        vehicle.run();
    }
}

public interface Vehicle{
    public void run();
}

Driver driver = new Driver();
Bus bus = new Bus();
dirver.drive(bus);
  • 만약 Bus 가 구현 클래스라면 다음과 같이 Driver drive() 메소드를 호출할 때 Bus 객체를 생성해서 매개값으로 줄수 있음. drive() 메소드는 Vehicle 타입을 매개변수로 선언했지만, Vehicle을 구현한 Bus 객체가 매개값으로 사용되면 자동타입 변환이 발생함
    Vehicle vehicle = bus
    
  • 매개변수의 타입이 인터페이스일 경우, 어떠한 구현 객체도 매개값으로 사용할 수 있고, 어떤 구현 객체가 제공되느냐에 따라 메소드의 실행결과가 다양해짐(매개변수의 다형성)

강제 타입 변환(Casting)

  • 구현 객체가 인터페이스 타입으로 자동 변환 시 인터페이스에 선언된 메소드만 사용 가능하다는 제약사항이 따름.
    • 인터페이스에는 3개의 메소드가 있고 클래스에는 다섯개의 메소드가 선언되어있다면, 인터페이스로 호출 가능한 메소드는 3개뿐임.
구현클래스 변수 = (구현클래스) 인터페이스 변수;

객체 타입 확인(instanceof)

  • 강제 타입 변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능
    if( vehicle instanceof Bus){
      Bus bus = (Bus) vehicle;
    }
    

인터페이스 상속

  • 인터페이스도 다른 인터페이스를 상속 가능하며, 클래스와는 달리 다중 상속을 허용함.
    public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 {...}
    
  • 하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라 상위 인터페이스의 모든 추상메소드에 대한 실체 메소드를 가지고있어야 함.
    하위인터페이스 변수 = new 구현클래스(..);
    상위인터페이스1 변수 = new 구현클래스(..);
    상위인터페이스2 변수 = new 구현클래스(..);
    

    하위 인터페이스로 타입 변환이 되면 상, 하위 인터페이스에 선언된 모든 메소드를 사용할 수 있으나, 상위 인터페이스로 타입 변환되면 상위 인터페이스에 선언된 메소드만 사용 가능하고, 하위 인터페이스에 선언된 메소드는 사용할 수 없다.

디폴트 메소드와 인터페이스 확장

  • 디폴트 메소드는 인터페이스에 선언된 인스턴스 메소드이기 때문에 구현 객체가 있어야 사용할 수 있다.

디폴트 메소드의 필요성

  • 인터페이스에서 디폴트 메소드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서 임.
  • 기존 인터페이스의 이름과 추상 메소드의 변경 없이 디폴트 메소드만 추가할 수 있기 때문에 이전에 개발한 구현 클래스를 그대로 하용할 수 있으면서 새롭게 개발하는 클래스는 디폴트 메소드를 활용할 수 있다.
    public default void method(){
      실행문;
    }
    

디폴트 메소드가 있는 인터페이스 상속

  • 부모 인터페이스에 디폴트 메소드가 정의되어 있을 경우, 자식인터페이스에서 디폴트 메소드를 활용하는 방법
    1. 디폴트 메소드를 단순히 상속만 받는다.
    2. 디폴트 메소드를 재정의(Override) 해서 실행 내용을 변경한다.
    3. 디폴트 메소드를 하위 인터페이스에서 추상 메소드로 재선언 한다.

카테고리:

업데이트: