슬기로운 개발생활

온라인 자바 스터디 #8 - 인터페이스

by coco3o
반응형

목표

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

학습할 것 (필수)

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

인터페이스

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메소드를 갖지만 

추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 일반 메소드 또는 멤버변수를 구성원으로 가질 수 없다.

오직 추상메소드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다.

 

  • 기존에는 인터페이스에 일반 메소드를 구현할 수 없었지만, 자바 8버전부터 default 예약어를 통해 일반 메소드구현이 가능하다.

인터페이스의 장점

  • 개발 시간 단축
    인터페이스가 작성되면 이를 사용해서 프로그램을 작성하는 것이 가능하다.
    메서드를 호출하는 쪽에서는 선언부만 알면 되기 때문이다.
  • 표준화 가능
    프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 하면 보다 일관되고 정형화된 프로그램의 개발이 가능하다.
  • 서로 관계없는 클래스들 간의 관계를 맺어준다
    하나의 인터페이스를 공통적으로 구현하도록 하여 관계를 맺어 줄 수 있다.
  • 독립적인 프로그래밍이 가능
    인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능하다.

인터페이스 정의

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 class 대신 interface를 사용한다.

interface에도 class와 같이 접근제어자로 public 또는 default를 사용할 수 있다.

  • 인터페이스는 static final 필드만 가질 수 있다.필드를 선언할 때public static final이 생략되어 있다고 생각하자.
  • 인터페이스에 적는 모든 메소드들은 추상 메소드로 간주된다.
  • 인터페이스 내에 존재하는 메소드는 무조건 "public abstract"로 선언되며, 이를 생략할 수 있다.
  • 인터페이스 내에 존재하는 변수는 무조건 "public static final"로 선언되며, 이를 생략할 수 있다.
interface 인터페이스 { 
         public static final 타입 상수이름 = 값;
         public abstract 메소드이름(매개변수);
}

인터페이스 구현

인터페이스는 구현한다는 의미의 키워드 'implements'를 사용한다.

public interface Animal {
    void sound();
}
public class Dog implements Animal {

    @Override
    public void sound() {
        System.out.println("멍멍");
    }
}
public class Lion implements Animal {

    @Override
    public void sound() {
        System.out.println("크아앙");
    }
}

여기서 중요한건 Animal인터페이스에 정의된 sound()메소드를

Dog 와 Lion 클래스에서 구현할 때 접근제어자를 public으로 했다는 것이다.

이렇게 오버라이딩 할 때는 부모의 메소드보다 넓은 범위의 접근 제어자를 지정해야한다.

 


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

다형성을 공부하면 자손클래스의 인스턴스를 부모타입의 참조변수로 참조하는 것이 가능하다는 것을 알 수 있다.

인터페이스도 이를 구현한 클래스의 부모라 할 수 있으므로 해당 인터페이스 타입의 참조변수로클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로 형변환도 가능하다.

public interface Animal {
    void sound();
}
ublic class Dog implements Animal {

    @Override
    public void sound() {
        System.out.println("멍멍");
    }

    public void sleep() {
        System.out.println("새근새근 잡니다.");
    }
}
public class Lion implements Animal {

    @Override
    public void sound() {
        System.out.println("크아앙");
    }

    public void hunting() {
        System.out.println("사냥을 합니다.");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal lion = new Lion();

        dog.sound();
        lion.sound();

      //  dog.sleep();     X 
      //  lion.hunting();  X
      
      ((Dog)dog).sleep(); 	  // O
      ((Lion)lion).hunting();     // O
    }
}

dog가 바라보고 있는 것은 Animal 인터페이스이기 때문에 dog.sleep()은 호출하지 못하므로

 ((Dog)dog).sleep() 으로 캐스팅하여 사용해야 한다.

반대로 Dog dog = new Animal(); 는 선언하지 못하고 컴파일 에러가 발생한다.


인터페이스 상속

자바에서 다중상속은 불가능하지만, 인터페이스는 예외이다.

인터페이스는 다중상속, 즉 여러 개의 인터페이스로부터 상속 받는 것이 가능하다.

인터페이스는 인터페이스로부터만 상속받을 수 있다.

 

자동차의 다양한 주행모드의 SportsMode, EchoMode, NormalMode를 예로 들어보자.

public interface EchoMode {

    void EchoMode();
}

public interface NormalMode {

    void NormalMode();
}

public interface SportsMode {

    void SportsMode();
}

아래의 Car 클래스는  3개 (EchoMode, SportsMode, NormalMode)의 인터페이스를 상속 받는다.

public class Car implements EchoMode, SportsMode, NormalMode{
    
    @Override
    public void EchoMode() {
        System.out.println("에코 모드로 주행 합니다.");
    }

    @Override
    public void NormalMode() {
        System.out.println("기본 모드로 주행 합니다.");
    }

    @Override
    public void SportsMode() {
        System.out.println("스포츠 모드로 주행 합니다.");
    }
}

 


인터페이스 기본 메소드 (default method), 자바 8

인터페이스는 기능에 대한 선언만 가능하기 때문에, 실제 코드를 구현한 로직은 포함될 수 없다.

하지만 자바8에서 이러한 룰을 깨트리는 기능이 나오게 되었는데, 그것이 default method이다.

메소드 선언시에 default를 명시하게 되면 인터페이스 내부에서도 코드가 포함된 메소드를 선언할 수 있다.

 

접근제어자에서 사용하는 default와 같은 키워드이지만, 접근제어자는 아무것도 명시하지 않은 접근제어자를 default라 하며

인터페이스의 default method는 'default'라는 키워드를 명시해야 한다.

interface MyInterface {
   default void printHello() {
      System.out.println("Hello World!");
      }
}

default라는 키워드를 메소드에 명시하게 되면 인터페이스 내부라도 코드를 작성 할 수 있다.

 

 

왜 사용할까?

사실 인터페이스는 기능에 대한 구현보다는, 기능에 대한 '선언'에 초점을 맞추어서 사용 하는데, 디폴트 메소드는 왜 등장했을까?

...(중략)... 바로 "하위 호환성"때문이다. 예를 들어 설명하자면, 여러분들이 만약 오픈 소스코드를 만들었다고 가정하자. 그 오픈소스가 엄청 유명해져서 전 세계 사람들이 다 사용하고 있는데, 인터페이스에 새로운 메소드를 만들어야 하는 상황이 발생했다. 자칫 잘못하면 내가 만든 오픈소스를 사용한 사람들은 전부 오류가 발생하고 수정을 해야 하는 일이 발생할 수도 있다. 이럴 때 사용하는 것이 바로 default 메소드다. (자바의 신 2권)

기존에 존재하던 인터페이스를 이용하여서 구현된 클래스를 만들고 사용하고 있는데,

인터페이스를 보완하는 과정에서 추가적으로 구현해야 할, 혹은 필수적으로 존재해야 할 메소드가 있다면,

이미 이 인터페이스를 구현한 클래스와의 호환성이 떨어지게 된다. 이러한 경우 default 메소드를 추가하게 된다면

하위 호환성은 유지되고 인터페이스의 보완을 진행 할 수 있다.

interface MyInterface {
    default void printHello() {
        System.out.println("Hello World");
    }
}
//구현체 생성
class MyClass implements MyInterface {
}

public class DefaultMethod {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.printHello(); //실행결과 Hello World 출력
    }
}

[정리]

-interface에서도 메소드 구현이 가능하다.

-참조 변수로 함수를 호출할 수 있다.

-implements한 클래스에서 재정의가 가능하다.


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

인스턴스 생성과 상관없이 인터페이스 타입으로 호출하는 메소드이다.

static 예약어를 사용하고, 접근제어자는 항상 public이며 생략 할 수 있다.

static method는 일반적으로 우리가 정의하는 메소드와는 다르다.

1. body가 있어야 한다.

2. implements 한 곳에서 override가 불가능하다.

public interface ICalculator {
 
    int add(int x, int y);
    int sub(int x, int y);
 
    default int mul(int x, int y) {
 
        return x * y;
    }
 
    static void print(int value) {
 
        System.out.println(value);
    }
}
public class CalcTest {
 
    public static void main(String[] args) {
 
        ICalculator cal = new Calculator();
 
        // cal.print(100); error
        ICalculator.print(100); 
        // interface의 static 메소드는 반드시 interface명.메소드 형식으로 호출
    }
}

static 메소드를 사용하는 데 주의해야할 점은 기존 클래스의 static 메소드처럼 class이름.메소드로 호출하는게 아니라

interface이름.메소드로 호출해야 한다.

100
 
Process finished with exit code 0

 

 


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

java8 에서는 default method와 static method가 추가 되었고,

java9 에서는 private method와 private static method가 추가 되었다.

 

java8의 default method와 static method는 여전히 불편하게 만든다.

단지 특정 기능을 처리하는 내부 method일 뿐인데도, 외부에 공개되는public method로 만들어야하기 때문이다.

interface를 구현하는 다른 interface 혹은 class가 해당 method에 엑세스 하거나 상속할 수 있는 것을 원하지 않아도, 

그렇게 될 수 있는 것이다.

 

java9 에서는 위와 같은 사항으로 인해 private method와 private static method라는 새로운 기능을 제공해준다.

→코드의 중복을 피하고 interface에 대한 캡슐화를 유지 할 수 있게 되었다.

public interface Car {
    void carMethod();

    default void defaultCarMethod() {
        System.out.println("Default Car Method");

        privateCarMethod();
        privateStaticCarMethod();
    }

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

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

DefaultCar.java 클래스 - Car 인터페이스 구현체

public class DefaultCar implements Car{

    @Override
    public void carMethod() {
        System.out.println("car method by DefaultCar");
    }
}
public class Main {
    public static void main(String[] args) {
        DefaultCar car = new DefaultCar();

        car.carMethod();
        car.defaultCarMethod();
    }
}
car method by DefaultCar
Default Car Method
private car method
private static car method

Process finished with exit code 0

references : 자바의 정석 2판

siyoon210.tistory.com/95

atoz-develop.tistory.com/entry/JAVA-8-interface-default-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%99%80-static-%EB%A9%94%EC%86%8C%EB%93%9C

www.notion.so/4b0cf3f6ff7549adb2951e27519fc0e6

 

 

 

반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기