interface Calculable{
double PI = 3.14;
int sum(int v1, int v2);
}
interface Printable{
void print();
}
class RealCal implements Calculable, Printable{
public int sum(int v1, int v2) {
return v1+v2;
}
public void print() {
System.out.println("This is RealCal!!");
}
}
class AdvancedPrint implements Printable{
public void print() {
System.out.println("This is RealCal!!");
}
}
public class InterfaceApp {
public static void main(String[] args) {
Printable c = new AdvancedPrint();
// new 우측에는 똑같은 인터페이스를 지정하는 클래스라면 어떤것이든지 가능(호환성(다형성) 보장)
// 어떠한 클래스가 데이터 타입을 무엇으로 하는지에 따라 다양한 모양이 가능함
c.print();
// c는 print()에는 접근 가능하지만, Calculable의 PI와 sum에는 접근 불가능하다.
}
}
인터페이스의 개념은 이해했지만, 언제 사용할 지 모를 때??
클래스의 기능이 너무 많아서 클래스의 기능을 구획화하고 선택적으로 사용자에게 제공하고 싶을 때
또는 협업할 때 의뢰하고 싶은 기능을 명확히 하거나
여러가지 목적의 클래스가 있을 때 그 클래스들이 공통적으로 가져야 할 변수나 메소드들이 있을 때
인터페이스를 사용해서 이러한 목적들을 이룰 수 있다.
// 인터페이스로 변경 위한 코드
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Tiger extends Animal {
}
class Lion extends Animal {
}
class ZooKeeper {
void feed(Tiger tiger) { // 호랑이가 오면 사과를 던져 준다.
System.out.println("feed apple");
}
void feed(Lion lion) { // 사자가 오면 바나나를 던져준다.
System.out.println("feed banana");
}
}
public class Sample {
public static void main(String[] args) {
ZooKeeper zooKeeper = new ZooKeeper();
Tiger tiger = new Tiger();
Lion lion = new Lion();
zooKeeper.feed(tiger); // feed apple 출력
zooKeeper.feed(lion); // feed banana 출력
}
}
interface Predator {
String getFood(); // 무조건 "feed apple" 이라는 문자열을 출력하는 문제를 해결하기 위함
}
}
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Tiger extends Animal implements Predator {
// 인터페이스의 메서드는 항상 public으로 구현해야 함
public String getFood() {
return "apple";
}
}
}
class Lion extends Animal implements Predator {
// 인터페이스의 메서드는 항상 public으로 구현해야 함
public String getFood() {
return "banana";
}
}
//class ZooKeeper {
// void feed(Predator predator) {
// System.out.println("feed apple");
// }
//}
// ZooKeeper클래스의 feed 메서드를 보면 호랑이가 오던지, 사자가 오던지 무조건 "feed apple" 이라는 문자열을 출력한다.
// 사자가 오면 "feed banana" 를 출력해야 함
class ZooKeeper {
void feed(Predator predator) {
System.out.println("feed "+predator.getFood());
}
}
// ZooKeeper 클래스는 위와 같이 작성해야 함
@1
자바8 버전 이후부터는 디폴트 메서드(default method)를 사용할 수 있다.
인터페이스의 메서드는 몸통(구현체)을 가질 수 없지만 디폴트 메서드를 사용하면 실제 구현된 형태의 메서드를 가질 수 있다.
// 예를들어 Predator 인터페이스에 다음과 같은 디폴트 메서드를 추가
interface Predator {
String getFood();
default void printFood() {
System.out.printf("my food is %s\n", getFood());
}
}
// 디폴트 메서드는 메서드명 가장 앞에 "default" 라고 표기
// Predator 인터페이스에 printFood 디폴트 메서드를 구현하면 Predator 인터페이스를 구현한 Tiger, Lion 등의 실제 클래스는 printFood 메서드를 구현하지 않아도 사용할 수 있다.
// 디폴트 메서드는 오버라이딩이 가능하다.
// 즉, printFood 메서드를 실제 클래스에서 다르게 구현하여 사용할수 있다.
@2
자바8 버전 이후부터는 인터페이스에 스태틱 메서드(static method)를 사용할 수 있다.
인터페이스에 스태틱 메서드를 구현하면인터페이스명.스태틱메서드명과 같이 사용하여 일반 클래스의 스태틱 메서드를 사용하는 것과 동일하게 사용할 수 있다.
interface Predator {
String getFood();
default void printFood() {
System.out.printf("my food is %s\n", getFood());
}
int LEG_COUNT = 4; // 인터페이스 상수
static int speed() {
return LEG_COUNT * 30;
}
}
// Predator.speed(); 이렇게 사용이 가능함.
// 인터페이스에 정의한 상수는 int LEG_COUNT=4; 처럼 public static final을 생략해도 자동으로 public static final이 적용됨