Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

기록하자..

인터페이스 | 백기선님 LIVE-STUDY 본문

자바

인터페이스 | 백기선님 LIVE-STUDY

P23Yong 2022. 5. 31. 15:48

인터페이스

학습할 것

  • 인터페이스 정의하는 방법
  • 인터페이스 구현하는 방법
  • 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
  • 인터페이스 상속
  • 인터페이스의 기본 메소드 (Default Method), 자바 8
  • 인터페이스의 static 메소드, 자바 8
  • 인터페이스의 private 메소드, 자바 9

인터페이스

인터페이스는 객체의 사용 방법을 정의한 타입이다. 인터페이스는 개발 코드와 객체가 서로 통신하는 접점 역할을 한다. 객체의 사용 설명서라고 생각하면 될 것 같다. 개발 코드가 인터페이스의 메서드를 호출하면 인터페이스는 객체의 메서드를 호출하게 된다. 이렇듯 개발 코드는 구체적인 객체의 내부 구조를 알 필요 없이 인터페이스의 구조만 알고 있으면 된다.

개발 코드가 직접 객체의 메서드를 호출하는 방법도 생각할 수 있지만, 개발 코드가 사용하는 객체를 자유롭게 변경하는데 있어서는 인터페이스를 사용하면 훨씬 편리하다. 인터페이스는 여러 객체의 사용이 가능하기 때문에 어떤 객체를 사용하느냐에 따라 리턴값이 다를 수 있다. 따라서 코드 변경 없이 실행 내용과 리턴값을 다양화 시킬 수 있다.

인터페이스 정의하는 방법

인터페이스의 작성은 클래스 작성과 같다. 대신 class키워드 대신 interface키워드를 사용해야 한다.

interface 인터페이스 { }

인터페이스는 클래스와는 다르게 상수와 메서드만을 구성 멤버로 가진다. 인터페이스는 개발 코드와 객체의 접점이기 때문에 객체를 생성할 수 없어서 생성자를 가질 수 없다. 자바 7 이전 까지는 인터페이스의 메서드는 실행 블록이 없는 추상 메서드로만 선언이 가능했지만, 자바 8부터는 디폴트 메서드와 정적 메서드까지 선언이 가능하다.

interface 인터페이스 {

    // 상수
    타입 상수이름 = 값;

    // 추상 메서드
    타입 메서드이름(매개변수, ...);

    // 디폴트 메서드
    default 타입 메서드이름(매개변수, ...) {...}

    // 정적 메서드
    static 타입 메서드이름(매개변수, ...) {...}
}
  • 상수
    • 인터페이스는 객체의 사용 설명서이기 떄문에 런타임시 값을 바꿀 수 있는 필드를 정의할 수 없다. public static final 키워드가 자동으로 컴파일 과정에서 붙는다.
  • 추상 메서드
    • 함수의 몸체 없이 선언부만 가지고 있다. 실제 몸체는 객체(인터페이스를 구현하는 객체)가 가지고 있다. public abstract가 자동으로 컴파일 과정에서 붙는다.
  • 디폴트 메서드
    • 함수의 몸체를 가지고 있다. 인터페이스에서 구현하고 있지만, 객체가 가지고 있는 인스턴스 메서드라 생각해야 한다.
  • 정적 메서드
    • 디폴트 메서드와 달리, 인터페이스만으로 호출이 가능하다.

인터페이스 구현하는 방법

객체의 사용 설명서를 가지고 있으니 이를 구현하는 객체를 생성해야 한다. 인터페이스에서 정의한 추상 메서드를 오버라이딩한 실제 메서드를 가진 객체를 인터페이스의 구현 객체라하고, 이를 생성하는 클래스를 구현 클래스라 한다.

구현 클래스는 클래스의 선언부에 implements 키워드를 붙이고 인터페이스명을 명시해야 한다. 그리고 인터페이스에 선언된 추상 메서드의 실체 메서드를 구현해야 한다.

public interface RemoteControl {

    void turnOn();
    void turnOff();
}
public class Tv implements RemoteControl {

    @Override
    public void turnOn() {
        System.out.println("TV를 킨다.");
    }

    @Override
    public void turnOff() {
        System.out.println("TV를 끈다.");
    }
}

주의해야할 점은 인터페이의 모든 메서드는 기본적으로 public 접근 제한을 가지기 때문에 public보다 더 낮은 접근 제한으로 구현할 수 없다.

익명 구현 객체

인터페이스는 원래는 인스턴스를 만들 수 없지만, 인터페이스르 구현하는 일회용 객체를 만들 수 있다. 이것이 익명 구현 객체이다.

RemoteControl rc = new RemoteControl() {
    public void turnOn() { System.out.println("~~"); }
    public void turnOff() { System.out.println("~~~"); }
};

코드 작성시 익명 구현 객체는 하나의 실행문이기 때문에 끝에는 세미콜론(;)을 반드시 붙여야 한다. new연산자 뒤에는 인터페이스의 이름과 중괄호가 따라온다. 중괄호에는 인터페이스의 추상 메서드들의 실체 메서드를 모두 작성해야 한다. 추가적으로 필드와 메서드를 선언할 수 있지미나, 익명 객체안에서만 사용할 수 있고 인터페이스 변수로 접근할 수 없다.

인터페이스 레퍼런스를 통해 구현체를 사용하는 방법

다형성의 특징을 이용해서 인터페이스의 타입을 통해 구현체를 사용할 수 있다.

다형성은 하나의 타입에 대입되는 객체에 따라서 실행 결과가 다양한 형태로 나오는 성질을 말한다.

interface Flyable {

    void fly();
}

interface Jumpable {

    void jump();
}

class Player implements Flyable, Jumpable {

    @Override
    public void fly() {
        System.out.println("Player can fly!");
    }

    @Override
    public void jump() {
        System.out.println("Player can jump!");
    }
}
Jumpable player = new Player();
player.jump();
player.fly();   // error! 

Jumpable을 사용해서 player를 선언하게 되면 Jumpable의 메서드만 사용할 수 있다.

인터페이스 상속

인터페이스도 클래스와 마찬가지로 다른 인터페이스를 상속할 수 있다. 클래스와의 차이점은 다중 상속이 가능하다는 점이다. extends 키워드를 통해 상속할 인터페이스들을 나열할 수 있다.

public interface Shape extends Drawable, Movable { ... }

하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 추상 메서드뿐만 아니라 상위 인터페이스의 추상 메서드까지 모두 구현해야한다. 그렇기 때문에 구현 클래스로부터 객체를 생성하고 하위 및 상위 인터페이스 타입으로 변환이 가능하다.

public class Circle implements Shape { ... }
Shape shape = new Circle();
Drawable drawable = new Circle();
Movable movable = new Circle();

인터페이스의 기본 메소드 (Default Method), 자바 8

자바 8부터 인터페이스에 인스턴스 메서드를 선언할 수 있게 되었다. 메서드 선언시에 default 키워드를 붙이게 되면 인터페이스 내부에서도 실제 코드가 포함된 메서드를 선언할 수 있다.

public interface Drawable {

    default void setPencilType(int type) {
        System.out.println("현재 타입은 " + type + " 타입입니다.");
    }
}

이런 디폴트 메서드를 추가한 이유는 기존 인터페이스의 확장성을 높여 새로운 메서드를 추가하기 위해서이다.
기존 A라는 인터페이스가 있고 이를 많은 사람들이 사용하고 있다. 그런데 A 인터페이스에 새로운 기능을 추가해야 하는 일이 발생했다. 이때 단순히 추상 메서드를 이용한다면 많은 사람들이 오류를 접하고 코드를 수정해야하는 일이 발생할 수 있다. 이를 위해 나온 것이 디폴트 메서드이다.

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

부모 인터페이스에서 디폴트 메서드가 정의되어 있는 경우, 자식 인터페이스에서 디폴트 메서드를 활용할 방법은 세 가지가 있다.

  • 디폴트 메서드를 단순히 상속 받는다.
  • 디폴트 메서드를 재정의해서 실행 내용을 변경한다.
  • 디폴트 메서드를 추상메서드로 재선언한다.
public interface Shape extends Drawable { ... }

다음과 같이 단순 상속 받는 경우 Shape의 구현 클래스는 setPencilType을 그대로 사용할 수 있다.

public interface Shape extends Drawable {

    @Override
    default void setPencilType(int type) {
        // 재정의
    }
}

setPencilType 메서드를 오버라이딩해서 자식 인터페이스를 구현하는 클래스는 자식 인터페이스의 setPencilType 메서드를 사용할 수 있다.

public interface Shape extends Drawable {
    @Override
    void setPencilType(int type);
}

다음과 같이 추상 메서드로 재선언하게 된다면, Shape를 구현하는 클래스는 setPencilType메서드의 실체 메서드를 모두 가지고 있어야 한다.

인터페이스의 static 메소드, 자바 8

정적 메서드는 디폴트 메서드와 마찬가지로 자바 8에서 추가된 인터페이스의 새로운 멤버이다. 형태는 다른 정적 메서드와 완전히 동일하다.

public interface Drawable {

    static void changePencil() {
        System.out.println("연필을 교환합니다.");
    }
}
public static void main(String[] args) {
    Drawable.changePencil();
}

다음과 같이 사용할 때는 인터페이스의 타입을 통해 사용한다.

인터페이스의 private 메소드, 자바 9

자바 9부터 인터페이스의 캡슐화가 가능해졌다. private 메서드와 private static 메서드를 사용가능하게 되었다.

private메서드의 등장은 외부에 공개되는 public메서드의 불편함을 해결할 수 있게 해준다. 또한 인터페이스 내부에서 코드의 재사용성을 향상시킨다. 예를 들어 두 개의 디폴트 메서드가 공유된 코드를 사용하고 있다면 private메서드는 이를 가능하게 해주고, 인터페이스를 구현하는 클래스에게 이 코드를 노출하지 않게 해준다.

private메서드는 다음 네 가지 규칙을 가지고 있다.

  • private 메서드는 추상 메서드가 될 수 없다.
  • private 메서드는 오직 인터페이스 내부에서만 사용할 수 있다.
  • private static 메서드는 다른 static, non-static인터페이스 메서드에서만 사용할 수 있다.
  • private non-static 메서드는 private static 메서드 내부에서 사용할 수 없다. -> 캡슐화
public interface CustomInterface {

    public abstract void method1();

    public default void method2() {
        method4();  // default 메서드 내부의 private 메서드
        method5();  // non-static 메서드 내부의 private static 메서드
        System.out.println("default method");
    }

    public static void method3() {
        method5(); // static 메서드 내부의 private static 매서드
        System.out.println("static method");
    }

    private void method4(){
        System.out.println("private method");
    } 

    private static void method5(){
        System.out.println("private static method");
    } 
}

public class CustomClass implements CustomInterface {

    @Override
    public void method1() {
        System.out.println("abstract method");
    }

    public static void main(String[] args){
        CustomInterface instance = new CustomClass();
        instance.method1();
        instance.method2();
        CustomInterface.method3();
    }
}
abstract method
private method
private static method
default method
private static method
static method

참고 - How do in java

참고 자료

이것이 자바다