자바 기본 복습 8. 인터페이스

장난·2021년 5월 29일
0

자바 기본

목록 보기
8/15
post-thumbnail

8주차 과제: 인터페이스


📌 목표

자바의 인터페이스에 대해 학습하세요.


📌 학습할 것

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

📜 시작에 앞서

  • 백기선 님의 라이브 스터디(2020년 11월부터 2021년 3월까지) 커리큘럼을 따라 진행한 학습입니다
  • 뒤늦게 알게 되어 스터디 참여는 못했지만 남아있는 스터디 깃허브 주소유튜브 영상을 참고했습니다

📑 인터페이스 정의하는 방법


인터페이스

  • 추상 메서드와 상수만을 맴버로 가질 수 있기 때문에, 상태가 없으므로 구현보다 역할에 집중할 수 있다
  • interface 예약어 사용해 정의

interface MyInterface{
    // 상수
	타입 상수명 =;
	
	// 추상 메서드
	리턴타입 메서드명(파라미터);

	// 디폴트 메서드
	default 리턴타입 메서드명(파라미터){
		...
	}

	// 정적 메서드
	static 리턴타입 메서드명(파라미터){
		...
	}
    
    // 프라이빗 메서드
    private 리턴타입 메서드명(파라미터){
        ...
    }
}
  • 인터페이스의 멤버변수는 상수만 가능하며 public static final을 입력하지 않아도 컴파일러가 자동으로 추가
  • 추상 메서드 역시 public abstract를 생략시 컴파일러가 자동으로 추가
  • java8에 추가된 default, static 메서드와 java9에 추가된 private 메서드에 대해서는 각 파트 참고

인터페이스가 추상클래스보다 추상적인데 추상클래스는 언제 사용?

  • 자바9 버전 이후 추상클래스 관점에서 인터페이스와의 차이점은 상태 존재 여부
public abstract class AbstractClass implements MyInterface{
    private String message = "상태 존재 여부";
    
    @Override
    public void printMessage(){
        sout(message);
    }
    
    public void setMessage(String message){
        this.message = message;
    }
}
  • 자바8 같은 경우 추가로 인터페이스에 프라이빗 메서드가 불가능하기 때문에 인터페이스에 중복이 많을 경우 추상 클래스 사용도 한 가지 방법

함수형 인터페이스


📑 인터페이스 구현하는 방법

  • implements 예약어 사용해 구현
class 클래스명 implements 인터페이스명 {
    ... //인터페이스에 정의된 추상메서드 모두 Override
}
  • extends 상속과 달리 implements A, B, C 같은 식으로 여러 인터페이스 다중상속 가능

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

  • 구현한 인터페이스로 형변환 가능
  • 인터페이스는 멤버변수 타입, 메서드 리턴 타입, 메서드 파라미터 등 여러 방면에 사용 가능

// [자바 기본 복습 6]의 다이나믹 메서드 디스패치 (Dynamic Method Dispatch) 예시
public class DMD {
    public static void main(String[] args) {
        Shape triangle = new Triangle();
        Shape square = new Square();

        triangle.printInfo();
        square.printInfo();
    }

    interface Shape {
        public void printInfo();
    }

    static class Triangle implements Shape {
        @Override
        public void printInfo() {
            System.out.println("Triangle");
        }
    }

    static class Square implements Shape {
        @Override
        public void printInfo() {
            System.out.println("Square");
        }
    }
}

/*
실행결과
Triangle
Square
*/
interface DiscountPolicy {
    ...
}

class FixedDiscountPolicy {
    ...
}

class RateDiscountPolicy {
    ...
}

public class OrderService {
    DiscountPolicy = new RateDiscountPolicy();
    ...
}

결합도

coupling

  • 느슨한 결합을 통해 추상화에 의존 가능

    • DiscountPolicy에 해당 인터페이스를 구현한 클래스가 "어떤" 메시지에 응답 해야할지 정해져있다
    • FixedDiscountPolicy, RateDiscountPolicy에는 메시지에 "어떻게" 응답할 것인지 내부적으로 구현돼있다
    • OrderServiceDiscountPolicy가 응답할 책임이 있는 메시지를 보내며 이때 어떤 구현체가 메시지에 응답할지는 몰라도 된다(즉, 어떻게 처리할지는 몰라도 된다) 따라서 다형성을 활용한 느슨한 결합이 가능하다

📑인터페이스 상속

  • 인터페이스는 인터페이스로부터만 상속 가능
  • 인터페이스 간 상속은 구현 코드를 통해 기능을 상속하는 것이 아닌, 형 상속(Type inheritance)
interface MyInterface1 {
    ...
}

interface MyInterface2{
    ...
}

interface MyMyInterface1 implements MyInterface1 {
    ...
}

interface MyMyInterface2 implements MyInterface1, MyInterface2 {
    ...
}
  • 이때 MyMyInterface1, MyMyInterface2 에 아무 내용이 없더라도 부모 인터페이스로 받은 메서드가 멤버로 포함

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

  • 메서드 구현부를 짜지 않는 기존 인터페이스 규칙을 깨고 나온 기본 메서드
  • default 예약어를 사용해 구현부까지 인터페이스에서 작성 가능
  • 인터페이스 구현체에 기본적으로 제공

interface MyInterface {
    default 리턴타입 메서드명(파라미터){
        ...
    }
}
  • Object 클래스의 메서드는 기본 메서드로 제공 불가 (구현체에서 재정의)

  • 기본 메서드 역시 구현체에서 재정의 가능

    • 인터페이스를 상속받는 인터페이스에서 다시 추상 메서드로도 가능

인터페이스의 메서드에 구현부를 왜 추가?

  • 변하지 않는 것은 없다
  • 아무리 설계를 잘해도 인터페이스에 새로운 메서드를 추가할 일이 생길 수 있다
  • 그런데 구현부 없이 추가한다면 해당 인터페이스를 구현한 모든 부분에 오류 발생
  • 이때 default 메서드가 있다면 하위 호환성 유지 가능
  • 물론 기본 메서드가 구현체 모르게 추가되므로 구현체에 따라 리스크 존재

두 인터페이스를 상속하는데 메서드 선언부가 같은 메서드가 있다면?

  • 컴파일 오류
  • 인터페이스를 구현한 클래스에서 해당 메서드를 오버라이딩해 해결
    • 특정 기본 메서드 선택하는 경우 {Instance}.super.{method} 형식으로 메서드 호출 가능

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

  • 인스턴스 생성과 상관없이 독립적으로 사용할 수 있는 메서드

  • 사용할 때는 인터페이스 이름으로 직접 참조

  • static 메서드는 오버라이드 불가


interface MyInterface1 {
    static void method() {
        System.out.println("static method");
    }
}

interface MyInterface2 {
    default void method() {
        System.out.println("default method");
    }
}

class MyClass implements MyInterface1, MyInterface2 {
    @Override
    public void method() {
        System.out.println("default method override");
    }
}

public class Test {
    public static void main(String[] args) {
        (new MyClass()).method();	// "default method override"
        MyInterface1.method();		// "static method"
    }
}
  • 인터페이스에서 접근하는 정적 메서드와 인스턴스로 접근하는 기본 메서드의 접근 영역이 다르기 때문에 이런 결과
  • 이때 MyClass에서 오버라이드 한 것은 물론 MyInterface2의 method()

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

  • 인터페이스 구현체에서 사용하거나 재정의할 수 없는 프라이빗 메서드 기능
  • 인터페이스를 구현체에서 공통적으로 사용하는 부분을 때어내서 코드 재사용성 높일 수 있다

interface MyInterface {
    private void privateMethod() {
        ...
    }
    private static void privateStaticMethod() {
        ...
    }
    default void defaultMethod() {
    	privateStaticMethod();
        privateMethod();
        ...
    }
}

📑📌📜✏️

0개의 댓글