인터페이스(Interface)
인터페이스는 장착하는 것.
[접근제한자] interface 인터페이스명 {
//상수
//추상메서드
}
1. 인터페이스는 상수와 추상메서드만 가질 수 있다.
-상수(public static final) => 한 번 저장된 값은 변경 불가하며, 인터페이스명으로 접근 가능.
-추상메서드(abstract method) => 상속받는 서브클래스에서 반드시 구현해야 함
=> 상수나 추상메서드 외의 생성자나 일반 변수, 메서드는 가질 수 없음.
2. 서브클래스에서 정의 시 extends가 아닌 implement(구현) 키워드를 사용해야 함.
=> 클래스에서는 다중 상속이 불가능하지만 인터페이스는 두개 이상을 상속(구현)받을 수 있다.
=> 인터페이스 끼리 상속은 extends 키워드 사용하며, 다중 상속 가능
=> 인터페이스에서는 메서드 구현이 불가능하므로 구현 대신 확장 사용.
3. 객체 생성 불가능하며, 상속 전용
=> 인터페이슬르 참조 변수 타입으로 사용 가능하며, 다형성 활용 가능함.
=> 추상메서드를 구현하지 않을 경우, 서브클래스를 추상클래스로 정의해야 함.
=> 강제성, 통일성 제공(추상클래스보다 강력한 강제성 부여)
interface 동물{
public abstract void 번식(); //추상메서드
}
interface 고래 extends 동물{}
interface 상어 extends 동물{}
//인터페이스 끼리는 extends 사용
class 고래상어 implements 고래, 상어{
//인터페이스를 구현받는 서브클래스에서는 반드시 추상메서드 구현 필수
//다중 상속 가능
//인터페이스 내의 모든 메서드가 추상메서드 이므로
//부모끼리의 중복되는 메서드에 대한 구별없이
//상속받는 서브클래스에서 직접 오버라이딩하므로 중복된 메서드로 인한 혼란이 없다.
public void 번식(){
System.out.println("알을 낳아 번식");
}
}
왜 인터페이스가 필요할까?
1.구현의 강제로 표준화(=코드의 통일성 향상)
-인터페이스의 추상메서드 제공을 통해 구현의 강제가 발생하면
서브클래스의 공통 메서드가 존재하게 되므로 다형성을 통해 코드의 통일성이 향상된다.
//레이저프린터와 잉크젯프린터의 공통특성인 프린트개념을 추출(추상화)해서
//상위 개념인 인터페이스로 정의했당
interface Printer {
public void print(String fileName);
}
//프린트 인터페이스를 상속받아 구현하는 서브클래스에서는
//반드시 프린트 메서드를 구현해야 하는 구현의 강제가 일어나 코드의 통일성이 향상됨
//보면 다 print()메소드로 이름을 통일함.
class LaserPrinter implements Printer{
@Override
public void print(String fileName){
System.out.println(fileName + "을 출력!");
}
}
class InkjetPrinter implements Printer{
@Override
public void print(String fileName){
System.out.println(fileName + "을 출력!");
}
}
//메인 메소드에서
LaserPrinter lp = new LaserPrinter();
lp.print("Ex.java");
//레이저 프린터에서 잉크젯으로 바꿔도 새로운 객체를 생성하여 메서드 호출 가능
InkjetPrinter ip = new InkjetPrinter();
ip.print("Ex.java);
2.모듈 교체 용이 = 다형성 활용
인터페이스 추상메서드 제공을 통해 1처럼 구현의 강제가 발생하면
서브클래스의 공통 메서드가 존재하게 되므로 다형성을 통해 코드의 통일성이 향상된다.
=> 업캐스팅 가능!
=> 지금까지 한 일,
잉크젯 프린터와 레이저 프린터 두 클래스가 존재했는데 이 둘을 각자 객체를 생성해서 이름이 다른 메서드 호출하는 것보다
둘의 공통 속성인 프린트 기능을 추출해 인터페이스로 정의함.
그래서 인터페이스를 상속한 잉크젯 프린터와 레이저 프린트는 강제로 구현을 표준화해야 하기 때문에
print라는 메서드를 오버라이딩 한다. 그래서 객체를 생성해서 호출할 때 print라는 메서드 하나로
참조변수만 다르게해서 호출 가능함
==> 하지만 참조변수는 같은데 호출했을 때 내용만 다르게 할 순 없을까?
업캐스팅 활용!!
Printer printer = lp;
printer.print("Ex.java");
//Printer로 업캐스팅
printer = ip;
//잉크젯을 프린터로 업캐스팅
그럼 printer.print() 메서드 안에 각자 다른 내용이 들어있게 됨
응용프로그램에서 프린터를 다루기 위한 PrintClient 클래스 정의한다고 가정함
외부로부터 프린트 객체를 전달받아 저장 가능한 멤버변수를 선언하고 setter로 초기화 수행
class PrintClient{
private Printer printer; //Printer이라는 타입의 변수
public void setPrinter(Printer printer)
this.printer = printer;
public void printThis(String fileName){
printer.print(fileName);
}
}
PrintClient pc = new PrintClient();
//실제 프린트 작업을 수행할 응용프로그램에서 setPrinter()메서드를 통해 프린트 객체를 전달받아
//저장하고 printThis()메서드를 호출하여 전달받은 프린터를 통해 출력
pc.setPrinter(lp);
pc.printThis("Ex.java");
셋 프린터로 프린터를 전달받아서 암튼 보면 알겠다
결론은 PrintClient클래스 내부에는 실제 프린터의 이름이 없으므로, 프린터가 바뀌어도 클래스를 수정할 필요가 없음
또한, 동일한 방법으로 서로 다른 프린터를 다룰 수 있음.
=> 즉, 서로 다른 프린터를 손쉽게 교체 가능하다! = 모듈 교체가 용이함
3.다형성 확장 => 관계없는 객체끼리 관계 부여 가능
서로 상속 관계가 없는 두가지 클래스에 새로운 상속 관계를 부여하기 위해서는 클래스는 불가능하며
인터페이스를 상속해 줄 수 있다!
기존의 상속관계와 달리 새로운 인터페이스를 정의하여 새로운 메서드를 추상메서드로 갖도록 구현하고
두가지 클래스에 해당 인터페이스의 추상메서드를 구현하면 굳이 업캐스팅 하지 않아도
인터페이스 타입으로 업캐스팅했을 경우 다형성 활용이 가능해진다!
ex. 스마트폰과 노트북 클래스의 공통 메서드인 charge()를 추상메서드로 갖는 chargeable 인터페이스 정의
class SmartPhone {
public void charge() {
System.out.println("SmartPhone 충전!");
}
}
class NoteBook {
public void charge() {
System.out.println("NoteBook 충전!");
}
}
//충전하는 메서드를 가진 두가지 클래스를 정의했당.
//이제 이 둘의 공통적인 특성인 충전이라는 추상메서드를 가진 인터페이스를 만들어 둘을 연결해줄 것
interface Chargeable {
public abstract void charge();
}
//그렇게 되면 위의 저 클래스 두개는 인터페이스를 구현하고 안의 추상메서드를 오버라이딩 해야함 ^^
// SmartPhone2 클래스 정의 - Phone 클래스 상속, Chargeable 인터페이스 구현
class SmartPhone2 extends Phone implements Chargeable {
// Chargeable 인터페이스의 추상메서드 구현 필수!
@Override
public void charge() {
System.out.println("SmartPhone2 충전!");
}
}
// NoteBook2 클래스 정의 - PC 클래스 상속, Chargeable 인터페이스 구현
class NoteBook2 extends PC implements Chargeable {
// Chargeable 인터페이스의 추상메서드 구현 필수!
@Override
public void charge() {
System.out.println("NoteBook2 충전!");
}
}
//스마트폰과 노트북 객체를 전달받아 충전하기 위한 iCharge() 메서드 생성
//=> 두 객체의 상속 관계는 Object 클래스 뿐만 아니라
//Chargeable 인터페이스까지 관계가 확장되었으므로 업캐스팅 가능함.
public static void iCharge(Chargeable obj){
// 공통 인터페이스인 Chargeable 내에 추상메서드 charge() 가 있으므로
// 타입 판별 없이 업캐스팅 된 객체 그대로 charge() 메서드 호출 가능!
obj.charge();
}
//그 다음, 인스턴스 생성해서 바로 집어넣기
Notebook nb = new NoteBook();
iCharge(nb);
//요 부분 헷갈;;;;
4.모듈간 독립적 프로그래밍 => 개발 기간 단축
0315 ex4 참고 먼말인지 헷갈린다