1.인터페이스 정의하는 방법
public interface 인터페이스명 {
//상수
타입 상수명 = 값;
//추상 메소드
타입 메소드명(매개변수, ... );
//디폴트 메소드
default 타입 메소드명(매개변수, ... ){
//구현부
}
//정적 메소드
static 타입 메소드명(매개변수) {
//구현부
}
}
상수 : 인터페이스에서 값을 정해줄테니 함부로 바꾸지 말고 제공해주는 값만 참조 (절대적)
추상메소드 : 가이드만 줄테니 추상메소드를 오버라이팅해서 재구현 (강제적)
default메소드 : 인터페이스에서 기본적으로 제공해주지만, 맘에 안들면 각자 구현(선택적)
정적메소드 : 인터페이스에서 제공해주는 것으로 무조건 사용 (절대적)
2.인터페이스 구현하는 방법
인터페이스에 정의된 추상 메서드를 완성하는 것
(implements를 사용한다는 것만 다르지, 추상 클래스 완성과 동일)
interface Fightable {
void move(int x, int y);
void attack(Unit u);
}
// Fighter 클래스는 Fightable 인터페이스를 구현
class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
일부만 구현하는 경우, 클래스 앞에 abstract를 붙여야 함
abstract class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
//public abstract void attack(Unit u) // 보이지 않지만 상속의 결과로 생략되어 있는 것
}
3.인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
새로운 인터페이스를 정의했다면 새로운 reference data type을 정의, data type으로 interface name 이용
interface type을 가진 reference variable을 정의한다면 이 객체는 인터페이를 구현하는 클래스의 인스턴스여야 함
public Object findLargest(Object object1, Object object2) {
Relatable obj1 = (Relatable)object1;
Relatable obj2 = (Relatable)object2;
if ((obj1).isLargerThan(obj2) > 0)
return object1;
else
return object2;
}
object1과 object2는 인터페이스 타입인 Relatable type으로 캐스팅될 수 있고 그래서 isLargerThan method를 사용 가능
4.인터페이스 상속
인터페이스의 조상은 인터페이스만 가능 (Object가 최고 조상 아님)
다중 상속이 가능 (∵ 추상 메서드는 충돌해도 문제 없음)
(상속에서 메서드 충돌문제 - 선언부가 똑같은데 구현부가 다른 것이 문제였음. 어느쪽을 상속받을지 결정할 수 없음)
// 구현부가 비었지만 상속 했으므로 멤버가 2개
interface Fightable extends Movable, Attackable { }
interface Movable{ void move(int x, int y); }
interface Attackable { void attack(Unit u); }
5.인터페이스의 기본 메소드 (Default Method), 자바 8
Default Method
인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
public interface PrintName {
void printName();
default void printNameUpperCase(){
System.out.println(getName().toUpperCase());
}
String getName();
}
해당 인터페이스를 구현한 클래스를 깨뜨리지않고 새 기능의 추가가 가능
기본 메소드는 구현체가 모르게 추가된 기능으로 리스크 발생 가능
ㄴ컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생 가능
ㄴ반드시 문서화가 필요하다 (@implSpec 태그 사용)
/**
* @ImplSpec
* 이 구현체는 getName()으로 가져온 문자열을 대문자로 변환 후 출력
*/
default void printNameUpperCase(){
System.out.println(getName().toUpperCase());
}
Object 가 제공하는 기능(equals, hasCode)는 기본메소드를 제공 불가
인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경 가능
인터페이스 구현체에서 재정의가 가능
6.인터페이스의 static 메소드, 자바 8
Static Method
해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공가능
public interface Foo {
static void helloAll(){
System.out.println("인삿말");
}
}
public class App {
public static void main(String[] args) {
//static 메소드 사용
Foo.helloAll();
}
}
7.인터페이스의 private 메소드, 자바 9
Private Method
인터페이스 내에서만 사용가능한 메서드
디폴트 메서드나 정적메서드에 사용하기 위해 작성되는 메서드
인터페이스를 구현하는 클래스쪽에서 재정의하거나 사용 불가
ㄴ 디폴트나 정적메서드를 통해서만 사용 가능
public interface Calc {
double PI = 3.14; //나중에 상수가됨
int ERROR = -9999999;
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 void description() {
System.out.println("정수 계산기를 구현합니다.");
myMethod(); //private 메서드 사용
}
//static메서드
static int total(int[] arr) {
int total = 0;
for(int i :arr) {
total+= i;
}
mystaticMethod();//private static 메서드 사용
return total;
}
//private 메서드
private void myMethod() {
System.out.println("private method");
}
//private static 메서드
private static void mystaticMethod() {
System.out.println("private static method");
}
}
private static 메서드는 인터페이스 내에서만 사용가능하고 static 키워드가 있기에 static 메서드안에서만 사용가능하기 때문에 total에 사용