인터페이스의 기본과 의미
추상 메소드만 담고 있는 인터페이스
인터페이스 메서드는 몸체 없이 세모콜론으로 마무리.
메소드의 몸체가 비어 있는 메소드를 가리켜, 추상메소드. -> 인터페이스로 생성 불가. 인터페이스는 상속이 아닌 구현을 목적으로 한다.
구현할 인터페이슬르 명시할 때 implements 사용
클래스를 둘 이상 사용 가능.
인터페이스의 형을 대상으로 참조변수 선언이 가능.
인터페이스의 추상 메서드와 이를 구현하는 메서드 사이에 오버라이딩 관계 성립
interface Printable {
void print(String doc);
}
class Printer implements Printable{
@Override
public void print(String doc){
System.out.println(doc);
}
}
public class Main1 {
public static void main(String[] args) {
Printable printable = new Printer();
printable.print("Hello JAva");
}
}
printable 참조변수를 선언할 수 있다. 인터페이스를 직접 혹은 간접적으로 구현하는 모든 클래스의 인스턴스를 참조 할 수 있다.
Printable printable = new Printer();
printable.print("Hello JAva");
이것 또한 메서드 오버라이딩이 적용. Printable 인터페이스의 print 메서드가 호출 되는 것이 아니라. 이를 구현한 Printer 클래스의 print 메소드가 호출. 오버라디잉 관계가 성립하기 때문에 실수 확률 감소
인터페이스 본질적 의미
연결점 또는 접점으로 둘 사이를 연결하는 매개체를 뜻
interface Printable2{
void printable(String doc);
}
class SPrinterDriver implements Printable{
@Override
public void print(String doc) {
System.out.println("From Samsung printer");
System.out.println(doc);
}
}
class LGPrinterDriver implements Printable{
@Override
public void print(String doc) {
System.out.println("From LG Printer");
System.out.println(doc);
}
}
public class Main2 {
public static void main(String[] args) {
String doc = "This is a report about ..";
Printable printable = new SPrinterDriver();
printable.print(doc);
System.out.println();
printable = new LGPrinterDriver();
printable.print(doc
);
}
}
마이크로소프트는 위 클래스 이름만 알면 내부적으로 구현이 어떻게 이루어지는지 알 필요 없다.
인터페이스의 문법 구성과 추상 클래스
추상 메소드, 디폴트 메소드, static 메소드가 있다. 그리고 인터페이스 간 상속이 가능. Instanceof 연산을 할 수도 있다.
인터페이스에 선언되는 메소드와 변수
인터페이스의 모든 메소드는 public이 선언된 것으로 간주.
반드시 선언과, 동시에 값으로 초기화
모든 변수는 publice, static, final 선언된 것으로 간주.
인터페이스 내에 선언된 변수는 상수 -> final static 으로 자동으로 선언
그래서 상수는 대문자로 작성. 인터페이스를 구현하는 클래스는 인터페이스에 존재하는 모든 추상메소드 구현
인터페이스 간 상속
interface Printable3{
void print(String doc);
}
class Prn204Drv implements Printable3{
@Override
public void print(String doc) {
System.out.println("204 Printer");
System.out.println();
}
}
class Prn731Drv implements Printable3{
@Override
public void print(String doc) {
System.out.println("7310");
System.out.println();
}
}
public class Main3 {
public static void main(String[] args) {
String myDoc = "This is a report about ..";
Printable3 printable3 = new Prn204Drv();
printable3.print(myDoc);
System.out.println();
printable3 = new Prn731Drv();
printable3.print(myDoc);
}
}
Printable 인터페이스의 print 추상 메소드는 흑백 출력을 위한 메소드.
interface Printable4{
void print(String doc);
}
interface ColoPrintable extends Printable3{
void printCMYK(String doc);
}
class Prn909Drv implements ColoPrintable{
@Override
public void print(String doc) {
System.out.println("909");
System.out.println();
}
@Override
public void printCMYK(String doc) {
System.out.println("909");
System.out.println();
}
}
public class Main4 {
public static void main(String[] args) {
String myDoc = "report";
ColoPrintable coloPrintable = new Prn909Drv();
coloPrintable.print(myDoc);
System.out.println();
coloPrintable.print(myDoc);
}
}
컬러 기능을 추가하려면 상속을 사용 하지 않으면 하나하나 기능을 추가해줘야 하지만, 상속을 활용하면 그만이다.
두 클래스 사이의 상속은 extends
두 인터페이스 사이의 상속도 extends로 명시
인터페이스와 클래스 사이의 구현만 implements로 구현
인터페이스의 디폴트 메소드
모든 인터페이스에 최소 한 개 이상의 추상 메소드를 추가해야 하는 상황 -> 디폴트 메소드를 사용.
interface Printable5{
void print(String doc);
default void printCMYK(String doc){
}
}
class Prn731Drv1 implements Printable5{
@Override
public void print(String doc) {
System.out.println("731-1");
System.out.println(doc);
}
}
class Prn909Drv1 implements Printable5{
@Override
public void print(String doc) {
System.out.println("909 - -");
System.out.println(doc);
}
@Override
public void printCMYK(String doc) {
System.out.println("909");
Printable5.super.printCMYK(doc);
}
}
public class Main5 {
public static void main(String[] args) {
String myDoc = "This is a report about";
Printable5 pr = new Prn731Drv1();
pr.print(myDoc);
System.out.println();
Printable5 pr1 = new Prn909Drv1();
pr1.print(myDoc);
}
}
default 선언이 붙은 메소드가 디폴트 메서드
default void printCMYK(String doc){
}
자체로 완전한 메소드
구현하는 클래스가 오버라이딩 하지 않아도 된다.
추가를 한다 해도 이전 코드에 영향을 주지 않는다.
디폴트가 등장한 이유는 인터페이스에 추상 메서드를 추가해야 할 상황에 개발해 놓은 코드에 영향을 미치지 않게 하기 위해서 처음 인터페이스를 설계하는 과정에서 디폴트 메서드를 적는다면 디폴트 메서드를 잘못이해.
인터페이스의 static 메소드 (클래스 메소드)
interface Printable6{
static void printLine(String str){
System.out.println(str);
}
default void print(String doc){
printLine(doc);
}
}
class Printer1 implements Printable6{
}
public class Main6 {
public static void main(String[] args) {
String myDoc = "report";
Printable6 printable6 = new Printer1();
printable6.print(myDoc);
Printable6.printLine("end");
}
}
Printable 인터페이스에는 구현해야 할 메소드가 존재하지 않는다. 이를 대상으로는 인스턴스 생성 불가.
class Printer1 implements Printable6{
}
보통은 인터페이스 default 메소드를 오버라이딩을 한다. 그러나 static 메소드를 확인하기 위헤 Override를 하지 않는다.
인터페이스에도 static 메소드를 정의할 수 있다.
인터페이스의 static 메소드 호출 방법은 클래스의 static 메소드 호출 방법과 동일
인터페이스 대상의 instanceof 연산
interface Printable7 {
void printLine(String str);
}
class SimplePrinter implements Printable7{
@Override
public void printLine(String str) {
System.out.println(str);
}
}
class MultiPrinter extends SimplePrinter{
@Override
public void printLine(String str) {
super.printLine("Start");
super.printLine(str);
super.printLine("end");
}
}
public class Main7 {
public static void main(String[] args) {
Printable7 printable7 = new SimplePrinter();
Printable7 printable71 = new MultiPrinter();
if (printable7 instanceof Printable7){
printable7.printLine("simple");
System.out.println();
}
if (printable71 instanceof Printable7){
printable71.printLine("Multi");
}
}
}
인터페이스의 또 다른 용도
마커 인터페이스에는 아무런 메서드도 존재 하지 않는 경우도 있다.
interface Upper{
}
interface Lower{
}
interface Printable9{
String getCons();
}
class Report implements Printable9, Upper{
String cons;
Report(String cons){
this.cons = cons;
}
@Override
public String getCons() {
return cons;
}
}
class Printer8{
public void printContents(Printable9 doc){
if (doc instanceof Upper){
System.out.println((doc.getCons()).toUpperCase());
} else if (doc instanceof Lower){
System.out.println((doc.getCons()).toLowerCase());
} else {
System.out.println(doc.getCons());
}
}
}
public class Main8 {
public static void main(String[] args) {
Printer8 print8 = new Printer8();
Report doc = new Report("Simple");
print8.printContents(doc );
}
}
핵심은
public void printContents(Printable9 doc){
if (doc instanceof Upper){
System.out.println((doc.getCons()).toUpperCase());
} else if (doc instanceof Lower){
System.out.println((doc.getCons()).toLowerCase());
} else {
System.out.println(doc.getCons());
}
}
메소드 호출에 의해서 문자열이 대문자 또는 소문자로 바뀌면서 새로운 String 인스턴스가 생성되어 반환.
class Report implements Printable9, Upper{
String cons;
Report(String cons){
this.cons = cons;
}
@Override
public String getCons() {
return cons;
}
}
printable 인터페이스를 구현하면서, 동시에 Upper인터페이스를 구현. 인스턴스가 printContents의 인자로 전달되면서 Upper 인터페이스를 구현-> 대문자로 출력
추상 클래스
하나 이상의 추상메서드를 갖는 클래스를 가리켜 추상 클래스라 한다.
하나의 추상 메소드를 갖고 있으니 추상 클래스이다. 클래스 선언부에 abstract 선언을 추가해야 한다. => 인터페이스 구현과 유사. 추상 클래스를 대상으로 인스턴스 생성도 불가능. 다른 클래스에 의해서 추상 메소드 구현이 되어야 한다.
따라서 이를 상속하는 하위 클래스에 의해서 구현되어야 할 메소드가 하나 이상 있는 경우를
“추상 클래스”