본문 바로가기

Java Live Study

Live Study 8주차 : 인터페이스

목표

자바의 인터페이스에 대해 학습하기

 

학습할 것

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

 


 

 

추상 클래스 : 추상 메소드(메소드 선언만 있는)외에 멤버 변수, 일반 메소드를 가질 수 있음

인터페이스 : 추상 메소드상수만을 가지는 추상 클래스 -> 다중 상속을 흉내 낼 수 있음

 

 

 

인터페이스 정의하는 방법

 

interface Man { // 인터페이스 선언
    public long ONE_SECOND = 1000; // 상수 선언, 반드시 초기화
    public long ONE_MINUTE = 60000;
    public void wakeup(); // 추상 메소드 선언, 끝에 ';' 사용
}

 

  • 인터페이스에 정의된 상수와 메소드의 접근 한정자는 'public'이 기본 (private, protected는 사용 불가)
    • 항상 상속받은 클래스에서 사용되어야 하기 때문이다.
  • 메소드는 구현 부분 없이 선언 부분만 정의 되어야 한다.
  • 인터페이스 내에는 추상 메소드의 선언이 허용된다.
  • 인터페이스를 포함하는 클래스는 인터페이스에 선언된 메소드를 반드시 public으로 선언해야 한다.

 


인터페이스 구현하는 방법

 

interface Man{ // 인터페이스 선언
    public long ONE_SECOND = 1000;
    public long ONE_MINUTE = 60000;
    public void wakeUp();
    public void sleep();
}

interface Worker{ // 인터페이스 선언
    public long WORK_TIME = 8;
}

public class Sleeper implements Man{ // 두 개의 인터페이스 포함
    public void wakeUp(){ // 메소드 오버라이딩
    	System.out.println("빨리 일어나세요!");
    }
    public void sleep(){ // 메소드 오버라이딩
    	System.out.println("빨리 잠드세요!");
    }
}

 

 

  • 인터페이스를 사용하기 위해서 implements 예약어를 사용한다.
  • 클래스에서 인터페이스를 포함하는 경우 인터페이스에서 정의된 모든 메소드를 클래스 내에서 반드시 오버라이딩 하여야 한다.
  • 클래스가 인터페이스를 포함하는 것을 상속의 개념으로 본다면, 클래스는 인터페이스를 다중 상속할 수 있다.
    • 즉 하나의 클래스가 상위 클래스를 여러개 가질 수 없지만, 다수 개의 인터페이스를 포함하는 것은 가능
    • 만약 클래스가 다수 개의 인터페이스를 포함한다면, 그 인터페이스에 선언된 모든 메소드를 오버라이딩 해야한다.

 

 

인터페이스로 구현 할 수 없는 것이 있기 때문에 여전히 abstract의 효용가치는 있다! (default, private.., spring security)

 

 


 

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

-> 인터페이스가 있을 때는 인터페이스 타입 기반으로 코딩해야한다

 

 

  • 인터페이스도 (추상 클래스와 같이) 다형성을 구현하는 데 사용될 수 있다.
    • 인터페이스를 포함하는 클래스를 작성할 경우, 인터페이스를 상위 클래스의 개념으로 취급하여 다형성 구현 가능.
  • 인터페이스의 형의 객체 변수에 그 인터페이스를 포함하는 클래스의 객체를 배정하여 인터페이스에서 선언된 메소드에 접근 가능
  • 다형성 측면에서는 인터페이스는 추상 클래스와 같은 형태로 사용된다.

 

abstract class Figure{ // 추상 클래스 선언
    abstract void draw();
}

interface Shape{ // 인터페이스 선언
    public void computeArea(double a, double b);
}

class Triangle extends Figure implements Shpae{ // 추상클래스와 인터페이스를 포함
    void draw(){ // 메소드 오버라이딩
    	System.out.println("삼각형 그리기 기능");
    }
    public void computeArea(double a, double h){ // 메소드 오버라이딩
    	System.out.println("삼각형 넓이 : " + (a*h/2));
    }
}

class Rectangle extends Figure implements Shape{
    void draw(){
        System.out.println("사각형 그리기 기능");
    }
    public void computeArea(double h, double v){
        System.out.println("사각형 넓이 : " + (h*v));
    }
}

class Polydraw{
    public void pdraw(Figure f){
        f.draw();
    }
    public void pcomputeArea(Shape s, double a, double b){
        s.computeArea(a, b);
    }
}

public class InterfaceTest{
    public static void main(String args[]){
        Polydraw p = new Polydraw();
        
        Figure fg1 = new Triangle();
        Figure fg2 = new Rectangle();
        
        Shape sp1 = new Triangle(); // 인터페이스 형의 객체 변수에 클래스의 객체 배정
        Shape sp2 = new Rectangle();
        
        p.pdraw(fg1);
        p.pcompute(sp1, 4, 4); // 인터페이스 형의 객체 변수를 이용하여 메소드 호출
        
        p.pdraw(fg2);
        p.pcompute(sp2, 4, 4);
   }
}

/* output
삼각형 그리기 기능
삼각형 넓이 : 8.0
사각형 그리기 기능
사각형 넓이 : 16.0
*/
        

 

 

<조금 더 간단한 예제>

  • Man 인터페이스의 구현체인 Sleeper 객체를 만든다.
  • 구현된 Sleeper 객체에서 Man 인터페이스에 선언된 추상 메소드를 사용할 수 있다.
public class ManTest{
    public static void main(String[] args) {
        // Sleeper 객체를 Man 인터페이스 타입으로 선언
        Man man = new Sleeper();
        man.wakeUp();
        man.sleep();
    }
}

 

 

 


인터페이스 상속

 

  • 인터페이스도 필요에 따라 다른 인터페이스로부터 상속받을 수 있다.
    • 인터페이스의 상속은 예약어 'extends'를 사용한다.
  • 인터페이스는 다중상속을 허용한다. (클래스는 다중상속이 허용되지 않는다)
    • 다중상속이란 하나의 클래스가 둘 이상의 클래스를 동시에 상속하는 것을 의미

 

<클래스 다중상속 코드>

// IPTV는 TV이자 Computer이다

class TV{
    public void onTV(){
        System.out.println("영상 출력 중");
    }
}
class Computer{
    public void dateReceive(){
        System.out.println("영상 데이터 수신 중");
    }
}

class IPTV extends TV, Computer{ // compile ERROR! -> 자바는 다중상속 지원x
    public void powerOn(){
        dataReceive();
        onTV();
    }
}

class CompileErrorEx(){
    public static void main(String args[]){
        IPTV iptv = new IPTV();
        iptv.powerOn();
        
        TV tv = iptv;
        Computer comp = iptv;
    }
}

 

하나의 클래스가 둘 이상의 클래스를 동시에 상속하는 코드 -> 다이아몬드 상속이 일어날 수 있음

 

 

UML을 이용해 표현한 다이아몬드 상속

 

 

  • 다이아몬드 상속이 구성되면
    • Employee 클래스에 정의된 메소드를, TechMarketer 클래스에서 호출하는 경우에 문제 발생
    • TechMarketer클래스는 Employee 클래스를 간접적으로 두 번 상속하기 때문에 호출할 메소드의 선택이 애매해지기 때문
    • 그래서 자바는 다중상속을 지원하지 않게하여 문제를 제한한다.

 

 

 

<클래스 다중 상속 코드>를 변경하여 <인터페이스를 이용하여 상속하기>

// IPTV는 TV이자 Computer이다

interface TV{
    public void onTV();
}
class TVImpl{
    public void onTV(){
        System.out.println("영상 출력 중");
    }
}

interface Computer{
    public void dateReceive();
}
class ComputerImpl{
    public void dataReceive(){
        System.out.println("영상 데이터 수신 중");
    }
}

class IPTV implements TV, Computer{
    ComputerImpl comp = new ComputerImpl();
    TVImpl tv = new TVImpl();
    
    public void dataReceive(){
        comp.dataReceive();
    }
    public void onTV(){
        tv.onTV();
    }

    public void powerOn(){
        dataReceive();
        onTV();
    }
}

class MultiInterfaceEx(){
    public static void main(String args[]){
        IPTV iptv = new IPTV();
        iptv.powerOn();
        
        TV tv = iptv;
        Computer comp = iptv;
    }
}

/* output
영상 데이터 수신 중
영상 출력 중
*/

 


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

 

인터페이스는 선언만 가능하고 구현을 할 수 없지만, 인터페이스의 default method에서는 구현이 가능하다!

 

 

인터페이스의 default method

  • 하위 호환성을 유지(기존 인터페이스를 유지)하면서 인터페이스에 새로운 메소드 추가 가능
  • Java 8부터 사용되었다.
  • 모든 인터페이스에 추가 가능

 

기존에 있던 Man 인터페이스에 새로운 기능 rest()를 추가하려 한다.

interface Man{
    public void wakeUp();
    public void sleep();
}

 

그렇다면 Man 인터페이스를 구현하는 '모든' 클래스에 rest()를 새로 구현해야 한다.

이때 default method를 사용하면, 인터페이스 내에서 구현이 가능하다.

interface Man{
    public void wakeUp();
    public void sleep();

    default void rest(){
        System.out.println("휴식 중입니다!");
    }
}

 

 


 

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

  • 인터페이스의 static method도 Java 8부터 사용 가능해짐 (이전 버전에서는 허용되지 않음)
  • 객체 없이 인터페이스로 바로 호출 가능

 

interface Man{
    public void wakeUp();
    public void sleep();

    default void rest(){
        System.out.println("휴식 중입니다!");
    }
    
    static void eat(){
    	System.out.println("밥 먹는 중입니다!");
    }
}

public class TestMan{
	public static void main(String args[]){
    	Sleeper sleeper = new Sleeper();
        sleeper.rest(); // default method
        Man.eat(); // static method
    }
}

 


 

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

 

  • 어떠한 메소드를 구현 할때 더 복잡한 메소드를 만드는 것이 좋다.
    • 그러한 코드는 재사용성, 유지, 이해하기가 더 쉬워지기 때문
    • 보통 이러한 목적을 가진 private method는 외부에서 볼 수 없고, 사용할 수 없음
  • Java 8에서는 인터페이스 내에서 private method를 만들 수 없지만,
  • Java 9에서는 인터페이스 내에서 private method를 만들 수 있다.

 

Java 9에서 이러한 private method를 만들면 가지게 되는 특징은?

  • method body가 있고, abstract가 아니다.
  • static 이거나 non-static 이거나
  • 구현한 클래스와 인터페이스는 상속되지 않음
  • 인터페이스로부터 method를 호출 할 수 있음

 

interface finalInterface{
    private static int static staticMethod(){
    	return 100;
    }
    
    private int nonStaticMethod(){
    	return 200;
    }
}

 

 

 


참고

 

 

'Java Live Study' 카테고리의 다른 글