목표
자바의 인터페이스에 대해 학습하세요.
학습할 것 (필수)
- 인터페이스 정의하는 방법
- 인터페이스 구현하는 방법
- 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
- 인터페이스 상속
- 인터페이스의 기본 메소드 (Default Method), 자바 8
- 인터페이스의 static 메소드, 자바 8
- 인터페이스의 private 메소드, 자바 9
1. 인터페이스 정의하는 방법
인터페이스란 일종의 규약이다. 예전에는 추상 클래스와 인터페이스의 차이를 두긴 했지만 자바 8의 static method와 default method의 등장으로 요즘은 크게 차이에 대한 의미를 두지 않는다.
인터페이스를 작성하는 방법은 클래스를 작성하는 것과 같다. 다만 키워드를 class -> interface로 바꿔서 사용한다는 것만 주의하면 된다. 인터페이스의 접근 제어자는 public or default(인터페이스 기본 메소드) 2가지만 사용할 수 있었지만 자바 9에서는 private도 사용 가능하다.
기본구조
interface 인터페이스이름 {
public static final 상수이름 = 값;
public abstract 메소드이름 (매개변수);
}
제약사항
1. 인터페이스 내 모든 멤버 변수는 public static final(상수) 이어야 하며, 생략 가능하다 (컴파일 시 컴파일러가 자동 추가)
2. 모든 메서드는 public abstract이어야 하며, 생략가능하다 (역시 컴파일러가 자동 추가, java 1.8 이후로 static메소드, 기본 메서드는 예외, 자바 9 이후로는 private도 가능하다)
함수형 인터페이스(Functional Inteface)
추상 메소드를 딱 한 가지만 가지고 있는 인터페이스를 의미한다. (추상 메소드가 아니라면 괜찮다.)
이러한 함수형 인터페이스를 SAM (Single Abstract Method) 인터페이스라고도 한다.
@FunctionalInterface 애노테이션을 붙이면 컴파일 시점에 checking 한다.
FunctionalInterface의 예
@FunctionalInterface
public interface RunSomething {
void doIt();
static void printName() {
System.out.println("hyangkeun");
}
default void printAge() {
System.out.println("28");
}
}
람다 표현식 (Lambda Expressions)을 이용하면 함수형 인터페이스의 인스턴스를 만들 때 코드를 줄일 수 있다.
public class Example {
public static void main(String[] args) {
// 익명 내부 클래스
RunSomething runSomething = new RunSomething() {
@Override
public void doIt() {
System.out.println("anonymous inner class");
}
};
// 이렇게 줄일 수 있다.
RunSomething runSomething1 = () -> System.out.println("anonymous inner class2");
runSomething.doIt();
runSomething1.doIt();
}
}
2. 인터페이스 구현하는 방법
인터페이스는 추상 클래스처럼 그 자체로는 인스턴스를 생성할 수 없다.
상속에서는 클래스를 "확장한다"는 의미의 키워드로 'extends'를 사용했지만 인터페이스는 "구현한다"는 의미를 가진 키워드인 'implements'를 사용한다.
일반적으로 인터페이스를 구현하는 클래스는 그 인터페이스가 가진 모든 추상 메서드를 재정의해서 몸체를 만들어야 하지만 abstract를 붙여서 추상 클래스로 선언하면 일부만 구현해도 된다. 좀 더 이해를 돕기 위해 코드로 확인해 보자
아래와 같이 LittleBoy라는 인터페이스가 있다.
PlayImpl는 abstract키워드를 붙여 play에 대해서만 재정의하고 있다.
StudyImpl은 play를 구현하지 않고 study만 구현하고 있다.
이런 식으로 abstract 키워드를 붙여서 추상 클래스로 선언하면 일부 메소드만 구현할 수 있으며 컴파일 오류 발생하지 않는다. 물론 인스턴스로 생성한다면 재정하지 하지 않았던 메소드는 생성하면서 재정의를 해줘야 한다.
3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
public interface Animal {
public void bark();
}
위 인터페이스를 구현한 Cat클래스와 Dog클래스가 있다고 가정하자
메인 메서드에서 아래와 같이 인스턴스 객체를 생성하고 각 인스턴스에 맞게 재정의된 메소드를 호출한다.
Cat cat = new Cat();
Dog dog = new Dot();
cat.bark();
dog.bark();
인터페이스 역시 구현한 클래스의 조상으로 볼 수 있으므로 해당 인터페이스 타입의 참조 변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로 형 변환이 가능하다.
Cat과 Dog 인스턴스는 Animal타입의 참조변수로 참조하는 것이 가능하다.
Animal cat = new Cat();
Animal dog = new Dog();
cat.bark();
dog.bark();
예
인터페이스의 이러한 다형성을 이용하면 다양한 정책이나 알고리즘 프로그램의 큰 수정 없이 적용, 확장할 수 있다.
(Bubble, Quick, Heap Sort는 Sorting을 구현한 것이다.)
JDBC의 DriverManager클래스도 인터페이스를 다형성으로 구현하는 방식으로 제공되어 있다.
Connection을 어떻게 execute, resultset, statement를 어떻게 할지에 대한 것들을 인터페이스화 하고
이걸 바탕으로 오라클, mssql, mysql 등 각각의 db회사들이 인터페이스 대한 구현을 만들어서 jar파일 형태로 제공한다.
리턴 타입이 인터페이스
리턴 타입이 인터페이스라는 것은 메소드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
아래와 같이 TestInterface라는 인터페이스가 있다.
public interface TestInterface {
public void test();
}
이 인터페이스를 구현한 Test클래스는 인스턴스 생성 시 test() 메서드를 무조건 호출하게 되어있다.
public class Test implements TestInterface {
public Test () {
test();
}
@Override
public void test() {
System.out.println("test입니다.");
}
}
리턴 타입이 인터페이스이기 때문에 return에서 TestInterface를 구현한 Test클래스의 인스턴스를 반환한다.
그리고 method2()를 호출하게 되면 Test의 test() 메서드를 호출하게 되어 콘솔 창에 "test입니다."가 나오게 된다.
public TestInterface method2() {
return new Test();
}
4. 인터페이스 상속
인터페이스는 인터페이스로부터만 상속을 받을 수 있으며, 기본 클래스에서는 다중 상속이 불가능하나 인터페이스에서는 다중 상속이 가능하다.
interface Fightable extends Movable, Attackable {
// 인터페이스는 인터페이스만 상속가능하다.
}
다중으로 구현도 가능하다
public class PlayImpl implements Little, Little2{
// Little과 Little2 두 가지를 구현하는 클래스
}
5. 인터페이스의 기본 메소드 (Default Method), 자바 8
프로그램을 운영할 때 유지보수 및 기능 추가를 해야 하는 경우가 생겼을 때 interface에 정의된 메서드를 추가하게 되면 이를 구현한 모든 클래스에 해당 메소드를 구현해야 했다. 하지만 default method의 등장으로 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있게 되었다.
기본 메소드란 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법이다.
public interface SomthingInterface {
void somthingPrint();
// 이 메소드를 나중에 추가 했다면
// 이 인터페이스를 구현한 클래스에서 에러발생하지 않는다 - default 인터페이스
default void newMethod(){
System.out.println("hi I'm new Method ");
}
void somethingDoing() {
System.out.println("hi hi");
}
}
기능이 막강한 만큼 주의 사항이 있다.
- Object가 제공하는 기능 (equals, hasCode)는 기본 메소드로 제공할 수 없다.
- 기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있어 문서화를 잘해야 한다.
6. 인터페이스의 static 메소드, 자바 8
Java 8에서 도입된 기능으로 인터페이스에 static 키워드가 추가 가능하다.
해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.
인터페이스를 구현한 클래스에서는 static 메서드를 오버라이딩 할 수 없다.
public class Main {
public static void main(String[] args) {
Animal.bark()
}
}
public interface Animal {
static void bark() {
System.out.println("static이므로 강제로 멍멍이라고 짖어");
}
}
7. 인터페이스의 private 메소드, 자바 9
자바 9부터 인터페이스에 접근제어자로 private이 가능하게 되었다.
static 메소드 같은 경우 무조건 public으로 선언되어야 하는 문제가 있어 자바 9부터는 캡슐화를 통해 정보은닉이 가능해졌다.
특징으로는 아래와 같이 3가지 정도 있는 것으로 보이나 추가적으로 피드백을 통해 배워야겠다.
- private메소드 이므로 몸체가 있어야 한다.
- 몸체가 있어야 하므로 abstract키워드를 사용할 수 없다.
- static메소드도 private으로 선언 가능하다.
REFERENCE
백기선, 더 자바 8
JAVA의 정석
'Java' 카테고리의 다른 글
9주차 과제: 예외 처리(피드백) (0) | 2021.01.17 |
---|---|
스터디 할래 9주차 과제: 예외 처리 (0) | 2021.01.16 |
7주차 과제: 패키지 (피드백, feedback) (0) | 2021.01.02 |
7주차 과제: 패키지 (0) | 2021.01.01 |
6주차 과제: 상속 (feedback, 피드백) (0) | 2020.12.27 |