본문 바로가기
Java

[자바 스터디] #8 - 인터페이스

by zannew 2021. 2. 16.

 

 

 목표

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

▣ 학습할 내용

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

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

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

  • 인터페이스 상속

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

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

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

 

▶8-1 인터페이스 정의하는 방법

클래스를 선언하는 것과 유사하다. class라는 키워드 대신 interface라는 키워드를 사용해서 선언한다.

interface Example{

}

접근지시자로는 public과 default를 사용할 수 있다. 보통 클래스의 멤버들과 달리 인터페이스의 멤버들은 제약조건이 있다.

-> (인터페이스에 선언된) 모든 멤버변수는 public static final이어야 하고, 이를 생략할 수 있다.

-> (인터페이스에 선언된) 모든 메서드는 public abstract여야 하고, 이를 생략할 수 있다. 

**생략된 접근제어자는 컴파일 타임에 컴파일러가 자동으로 추가해주기 때문에 생략할 수 있다.

BUT!!! JDK 1.8 부터 추가된 static method와 default method는 구현 강제성을 낮추고 유연하게 구현할 수 있도록  개선되었다.

 

▶8-2 인터페이스 구현하는 방법

추상클래스와 마찬가지로 그 자체로는 인스턴스를 생성할 수 없고, 인터페이스도 추상클래스와 같이 인터페이스 안에 정의된 멤버들을 사용해 구현해줄 클래스를 작성해야한다. 추상클래스는 확장하는 의미의 'extends' 키워드를 사용하지만 인터페이스는 구현한다는 의미의 'implements' 키워드를 사용한다.

public interface Example {

}

public class ExampleImpl implements Example {
	
	
}

 

구현 가능한 방법들을 나열하자면,

1. 단일 구현 (1개의 인터페이스) : 하나의 인터페이스만 구현

public interface Cafe { 

}

public class Coffee implements Cafe {
	
}

 

2. 다중 구현 : 여러개의 인터페이스를 구현

public interface Drink {

}

public interface Dishes {

}

public class Menu implements Drink, Dishes {

}

 

3. 상속과 구현을 동시에 : 하나의 추상클래스를 상속받고, 1~N개의 인터페이스를 구현한다. 

public interface Korean {

}

public interface Asian {

}

public abstract class Person {

}

public class Student extends Person implements Asian, Korean {

}

 

▷ 인터페이스와 추상클래스의 차이점

인터페이스는 추상클래스처럼 추상메서드를 갖고 있지만 추상클래스보다 추상화 정도가 높다. 

추상클래스는 바디를 가진 일반메서드 또는 멤버변수를 가질 수 있지만 인터페이스는 추상메서드와 상수만 멤버로 가질 수 있다. 

추상클래스는 "is-a : ~는 ~이다" 개념이라면, 인터페이스는 "has-a : ~는 ~를 가질 수 있다.(할 수 있다.)"의 개념으로 구분지을 수 있다.

 

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

public interface Animal {
	String getName();
    int getLegs();
}

public class Tiger implements Animal {
	@Override
    public String getName(){
    	return "호랑이";
    }
    
    @Override
    public int getLegs(){
    	return 4;
    }
}

public class Bird implements Animal {
	@Override
    public String getName(){
    	return "새";
    }
    @Override
    public int getLegs(){
    	return 2;
    }
}

Animal 인터페이스를 선언하고 추상메서드를 선언하고 Tiger와 Bird클래스에서 Animal 인터페이스를 구현한다.

 

Tiger tiger = new Tiger();
Bird bird = new Bird();

System.out.println(tiger.getName());	// 호랑이
System.out.println(tiger.getLegs());	// 4

System.out.println(bird.getName());		// 새
System.out.println(bird.getLegs());		// 2

각 클래스의 인스턴스를 생성하고 오버라이드해서 구현된 메서드들을 호출할 수 있다.

 

Animal tiger = new Tiger();
Animal bird = new Bird();


public void printAnimal(Animal animal){
	System.out.println("이름 : "+animal.getName());
	System.out.println("다리 개수 : "+animal.getLegs());
}

printAnimal(tiger);
printAnimal(bird);

객체 지향 언어의 특징인 다형성(Polymorphism)을 활용하여 Animal 타입으로 인스턴스 생성도 가능하다. Animal타입의 파라미터를 받는 메서드가 있다면 위의 예시처럼 Tiger와 Bird타입의 인스턴스도 인자로 사용될 수 있다. 

 

▶8-4 인터페이스 상속

인터페이스는 인터페이스로부터만 상속받을 수 있다. 클래스와 달리 다중상속, 즉 여러 인터페이스로부터 상속받는 것이 가능하다. (extends 키워드를 사용한다고 다중상속이 불가능한 게 아니다..)

※ 참고로 인터페이스는 클래스와 달리 Object와 같은 최상위 인터페이스가 존재하지 않는다.

interface A {
	void testAMethod();
}

interface B {
	void testBMethod();
}

interface C extends A, B { }	// OK!

 

인터페이스 C에 선언된 멤버가 없지만 부모 인터페이스로부터 상속받은 두 개의 추상메서드 testAMethod와 testBMethod를 자동으로 멤버로 갖게된다.

 

▶8-5 인터페이스의 기본 메서드 (Default Method), 자바 8

 

기존 인터페이스에는 추상메서드만 선언할 수 있었는데 자바 8버전부터 default 메서드가 도입되었다. 인터페이스에 메서드를 추가한다는 것은, 이를 구현하는 모든 클래스들이 추가된 메서드를 override해야하므로 번거로운 작업이 될 수 있다. 8버전부터 추가된 default 메서드를 선언하면 기본적인 구현을 제공하는 메서드로 정의내리기 때문에 해당 인터페이스를 구현한 클래스들이 추가된 메서드를 override할 의무가 없어진다. 

 default 메서드는 앞에 키워드 default를 붙이고 이 역시 접근제어자는 public 이며 생략이 가능하다. 예외적으로 해당 인터페이스의 default 메서드와 구현 클래스의 메서드명이 일치하여 충돌이 생긴다면 override해서 메서드 간의 충돌을 방지한다. (인터페이스의 default메서드는 static메서드와 달리 상속이 가능하다.)

▷ default 메서드가 생긴 이유?

주된 이유는 라이브러리 업데이트 때문이라고 한다. 인터페이스는 라이브러리나 프레임워크에서 매우 많이 사용되는데 라이브러리를 업데이트할 때 인터페이스에 추가된 기능이 있다면 이를 구현한 클래스를 역시 같이 추가해줘야했다. 하지만 라이브러리 사용자가 해당 인터페이스를 구현한 클래스가 있다면 아직 구현되지 않은(오버라이드 되지 않은) 메서드가 있다고 컴파일 에러가 날 것이다. 이런 불편을 해소하기위해 default 메서드가 도입되었다고 한다.

 

 

▶8-6 인터페이스의 static 메서드, 자바 8

 

static 메서드 역시 자바 8버전부터 도입되었고 인스턴스와 관계없이 독립적인 메서드이기 때문에 인터페이스에 추가될 수 있었지만 인터페이스의 모든 메서드는 추상 메서드여야한다는 원칙을 깨지는 않았다. 이 원칙 때문에 인터페이스와 관련된 static 메서드는 별도의 클래스에서 정의내려야 했다. 

대표적인 예는 Collections 클래스를 예로 들 수 있다. Collection 인터페이스 관련 static메서드들이 예전부터 존재하던 규칙때문에 Collections라는 클래스를 따로 만들게 되었다.

 

▷인터페이스의 default 메서드와 static 메서드를 적용한 예시

public interface Calculator {

	public int plus(int a, int b);
    public int multi(int a, int b);
    
    default int execPlus(int a, int b){
    	return a+b;
    }
    static int execMulti(int a, int b){
    	return a*b;
    }

}

public class CalculatorImpl implements Calculator {

	@Override
    public int plus(int a, int n){
    	return a+b;
    }
    
    @Override
    public int multi(int a, int b){
    	return a*b;
    }
}


public class InterfaceEx {

	public static void main(String[] args){
    	
        Calculator cal = new CalculatorImpl();
        
        int resultPlus = cal.plus(1,2);
        int resultMulti = cal.multi(1,2);
        System.out.println(resultPlus);		// 3
        System.out.println(resultMulti);	// 2
        
        int resultExecPlus = cal.execPlus(1,5);
        System.out.println(resultExecPlus);		// 6
        
        int resultExecMulti = Calculator.execMulti(1,5)	// 5
        System.out.println(resultExecMulti);
        
    }
}

// 출처 : https://dahyeee.tistory.com/entry/JAVA-interface-default-static%EB%A9%94%EC%86%8C%EB%93%9C

 

 

▶8-7 인터페이스의 private 메서드, 자바 9

 

자바 8버전 부터 가능해진 디폴트 메서드 사용으로 로직을 분리할 필요가 생겼다. 

-> private 메서드는 인터페이스에서 반드시 구현을 마쳐야하며 추상메서드일 수 없다.

-> 구현체에서 구현할 수 없고, 자손 인터페이스에서도 상속이 불가능하다. 인터페이스

-> static/non-static 관계없이 메서드에 private 키워드를 붙일 수 있다.

 

 

 

 

 

 

백기선님의 자바 라이브 스터디 커리큘럼을 따라 공부하고 있습니다. 

잘못된 점이나 보충할 부분이 있으면 코멘트 남겨주세요

작은 조언이 저에겐 성장의 원동력이 됩니다 :-)

 

 

댓글