인터페이스는 클래스나 프로그램이 제공하는 기능을 명시적으로 선언하여주는 클래스나 프로그램이 제공하는 명세이다.
인터페이스를 사용하면 클라이언트 프로그램들은 인터페이스에 선언된 메서드 명세만을 보고 이를 구현한 클래스를 사용할 수 있어서 편리하다.
어떤 객체가 하나의 인터페이스 타입이라는 것은 그 인터페이스가 제공하는 모든 메서드를 구현했다는 의미이다. (하나의 클래스가 인터페이스를 implements 받은 것은 구현코드의 상속이 아니라서 타입상속을 받았다고 한다.)
하나의 인터페이스로 선언된 명세를 이용하여 여러 다양한 객체를 구현하여 사용하는 것이 자바의 특성중 하나인 다형성이다.
구현코드가 없는 추상 메서드로만 구성되어있다.
메서드를 선언하면 모든 메서드가 public abstract로 컴파일된다.
구현 class는 interface의 모든 abstract method들을 overriding하거나 class를 abstract class로 만들어야한다.
구현코드가 없어서 멤버변수를 가질 수 없고 모든 변수는 상수로 선언된다.
public static final로 컴파일된다.
interface 인터페이스 이름{
public static final float pi = 3.14F;
public void makeSomething();
}
Java 8부터는 default method와 static method가 생겨 일부 구현 코드들도 존재한다.
default void description() {
System.out.println("정수의 사칙연산을 제공합니다.");
myMethod(); // private method
myStaticMethod(); // private static method
}
static int total(int[] arr) {
int total = 0;
for (int num: arr) {
total += num;
}
//myMethod(); //private method라 오류발생
myStaticMethod(); // private static method라 호출 가능
return total;
}
private void myMethod() {
System.out.println("myMethod");
}
private static void myStaticMethod() {
System.out.println("my Static Method");
}
Calc calc = new CompleteCalc();
// Calc는 interface, CompleteCalc는 Calc를 구현한 class
Calc.java (interface)
package ch14;
public interface Calc {
double PI = 3.14;
int ERROR = -999999;
int add(int num1, int num2);
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
// default method는 위의 method와는 다르게 이 interface를 implement하는 클래스에서
// 꼭 재정의를 하지 않아도 사용가능하다. (원하면 재정의도 가능)
default void description() {
System.out.println("정수의 사칙연산을 제공합니다.");
myMethod();
myStaticMethod();
// default method에서는 private메서드를 기본, static둘 다 호출 가능하다.
}
// interface에서 static으로 생성한 method는 인스턴스 없이 사용 가능하다!!
static int total(int[] arr) {
int total = 0;
for (int num: arr) {
total += num;
}
//myMethod();
myStaticMethod();
// static method에서 private method를 호출할때는 private static만 호출가능하다.
return total;
}
private void myMethod() {
System.out.println("myMethod");
}
private static void myStaticMethod() {
System.out.println("my Static Method");
}
}
Calculator.java (Calc를 구현한 class)
package ch14;
public abstract class Calculator implements Calc {
// interface를 implement하면 method들의 overriding을 하거나
// class를 abstract로 만들어야하는데 이 경우는 4개중 2개의 method들만
// overriding을 하였기에 class도 abstract가 된다.
@Override
public int add(int num1, int num2) {
// TODO Auto-generated method stub
return num1 + num2;
}
@Override
public int substract(int num1, int num2) {
// TODO Auto-generated method stub
return num1 - num2;
}
}
CompleteCale.java (Calculator를 상속받은 class)
package ch14;
public class CompleteCalc extends Calculator{
@Override
public int times(int num1, int num2) {
// TODO Auto-generated method stub
return num1 * num2;
}
@Override
public int divide(int num1, int num2) {
// TODO Auto-generated method stub
if (num2==0)
return ERROR;
return num1/num2;
}
public void showInfo() {
System.out.println("모두 구현하였습니다. ");
}
/*
@Override
public void description() {
// TODO Auto-generated method stub
System.out.println("Complete overriding");
} // default method를 재정의한 예시
*/
}
CalculatorTest.java (Test code)
package ch14;
public class CalculatorTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {1,2,3,4,5};
System.out.println("Static method test: " + Calc.total(arr));
// interface에서 total은 static으로 생성한 method임으로 Calc를 통해 만든 class가 없더라도
// Calc interface를 통해 total method를 사용할 수 있다.
// 즉. interface에서 static으로 생성한 method는 인스턴스 없이 사용 가능하다!!
int num1 = 10;
int num2 = 2;
Calc calc = new CompleteCalc();
// CompleteCalc는 Clac로부터 타입 상속을 받았다.
// CompleteCalc는 Clac로부터 타입을 상속받아서 인스턴스 생성의 타입을 Calc로 해도 된다.
// 그대신 Calc에 정의된 method들만 사용 가능하다. (CompleteCalc에 추가적으로 method를 만들면 사용 불가.)
// CompleteCalc에 추가적으로 정의한 method를 사용하면 인스턴스의 타입을 CompleteCalc로 생성하면 된다.
System.out.println(calc.add(num1, num2));
System.out.println(calc.substract(num1, num2));
System.out.println(calc.times(num1, num2));
System.out.println(calc.divide(num1, num2));
// calc.showInfo();
calc.description();
}
}
자바의 인터페이스는 구현 코드가 없어서 하나의 클래스가 여러 인터페이스를 구현할 수 있다.
-> 인터페이스는 다중 상속이 가능하다는 의미
default method가 중복되는 경우는 구현 class에서 해당 default method를 재정의해야한다.
default method의 재정의의 경우 super를 사용하여 interface의 method를 읽어와 재정의해도 되며 아예 새로 재정의하여도 된다.
인터페이스 사이에도 상속을 할 수 있으며 이럴때는 extends를 사용한다.
여러 interface를 구현한 클래스를 인터페이스 타입으로 형 변환 하는 경우, 형변환하는 인터페이스에 선언된 메서드만 사용가능하다.
ex)
위 사진의 구조에서 Buy와 Sell이 동일한 default method를 사용하는 경우 default method는 Customer class에서 재정의하여야하며, 인스턴스를 생성할때 Upcasting을 하여 class를 생성하는 경우 해당 interface에서 선언된 method만 사용가능하다.