인터페이스는 정해진 규칙에 맞게 구현하도록 스펙을 정의하고 제시하는 데 사용되는(표준화) 기본 설계도이자 추상화를 달성하기 위한 메커니즘이다.
interface 인터페이스이름{
public static final 데이터타입 상수이름 = 값;
public abstract 메서드이름(매개변수 목록);
}
interface Human{
void move();
void speak();
}
interface Person extends Human(){}
class Manager extends Employee implements Human{
public void move(){}
public void speak(){}
}
class Manager extends Employee implements Human{
public void move(){}
public void speak(){}
}
Employee e = new Manager();
Human h = new Manager();
//Human 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 받는 메서드 정의
void work(Human h){
...
}
Flyer라는 interface를 선언하고 Airplane에서 Flyer를 implements하였다.
public interface Flyer{
public void takeOff();
public void land();
public void fly();
}
public class Airplane implements Flyer{
@Override
public void takeOff(){
System.out.println("비행기가 이륙하다");
}
@Override
public void land(){
System.out.println("비행기가 착륙하다");
}
@Override
public void fly(){
System.out.println("비행기가 날다");
}
}
Flyer라는 interface에 기능을 선언하여 관련(상속관계가 아닌) class를 interface type으로 묶을 수 있다.
fly()라는 기능은 서로 관련 없는 클래스지만 비행기도, 새도, 슈퍼맨도 할 수 있다.
Flyer하는 하나의 type으로 선언되어 사용될 수있다.
interface Drawable{
void draw();
}
class Rectangle implements Drawable{
public void draw(){
System.out.println("직사각형 그리기");
}
}
class Circle implements Drawable{
public void draw(){
System.out.println("원 그리기");
}
}
public class TestInfDrawable{
public static void main(String[] args){
Drawable d = new Circle();
d.draw();
}
}
public class Bird extends Animal implements Flyer{
@Override
public void takeOff(){ //interface implements
System.out.println("새가 이륙하다");
}
@Override
public void land(){ //interface implements
System.out.println("새가 착륙하다");
}
@Override
public void fly(){ //interface implements
System.out.println("새가 날다");
}
public void buildNest(){
System.out.println("새가 둥지를 짓다");
}
public void layEggs(){
System.out.println("새가 알을 낳다");
}
@Override
public void eat(){ //Animal eat() override
System.out.println("새가 먹는다");
}
}
interface Printable{
void print();
}
interface Showable{
void show();
}
public class MultipleInfTest implements Printable, Showable{
@Override
public void print(){
System.out.println("안녕!");
}
@Override
public void show(){
System.out.println("반가워");
}
public static void main(String[] args){
MultipleInfTest obj = new MultipleInfTest();
obj.print();
obj.show();
Printable p = new MultipleInfTest();
Showable s = new MultipleInfTest();
p.print();
//p.show(); <- Printable 인터페이스 타입의 메서드만 호출 가능
s.show();
}
}
interface Drawable{
void draw();
default void msg(){
System.out.println("interface default method");
privateMsg();
}
static void staticMsg(){
System.out.println("interface static method");
privateStaticMsg();
}
private void privateMsg(){
System.out.println("\t-> interface private method");
}
private static void privateStaticMsg(){
System.out.println("\t-> interface private static method");
}
}
class Rectangle implements Drawable{
@Override
public void draw(){
System.out.println("Rectangle class draw method");
}
}
public class TestInfDefaultMethod{
public static void main(String[] args){
Drawble d = new Rectanle();
d.draw();
d.msg();
Drawable.staticMsg();
}
}
[결과]
Rectangle class draw method
interface default method
-> interface private method
interface static method
-> interface private static method
public interface Serializable{
}
public interface Cloneable{
}
interface interface_name{
interface nested_interface_name{
}
}
class class_name{
interface nested_interface_name{
}
}
public class View{
public interface OnClickListener{
public void onClick(View view);
}
}
중첩 인터페이스에 직접 접근할 수 없기 때문에 Showable 인터페이스로 Message 인터페이스에 접근하고 있다.
interface Showable{
void show();
//중첩 인터페이스 Message
interface Message{
void msg();
}
}
class TestNestedInterface implements Showable.Message{
@Override
public void msg(){
System.out.println("안녕! nested interface");
}
public static void main(String[] args){
Showable.Message message = new TestNestedInterface();
message.msg();
}
}
javap로 확인해보면 NestedMember로 표기된다.
…
#1 = Class #11 // ch11/nestedinf/Showable
#3 = Class #13 // ch11/nestedinf/Showable$Message
…
NestedMembers:
ch11/nestedinf/Showable$Message
클래스 내에서 인터페이스를 정의하는 방법은 인터페이스 내에서 정의하는 방법과 크게 차이는 없다.
class A{
interface Message{
void msg();
}
}
class TestNestedInterface implements A.Message{
public void msg(){
System.out.println("안녕! nested interface");
}
public static void main(String[] args){
A.Message message = new TestNestedInterface();
message.msg();
}
}
javap로 확인해보면 NestedMember로 표기된다.
…
#7 = InterfaceMethodref #9.#25 // ch11/nestedinfclass/A$Message.msg:()V
#9 = Class #38 // ch11/nestedinfclass/A$Message
…
9:invokeinterface #7, 1 // interfaceMethod ch11/nesatedinfclass/A$Message.msg:()V
| 추상 클래스(abstract class) | 인터페이스(interface) |
|---|---|
| 추상 메서드와 일반 메서드를 같이 가질 수 있다. | 추상 메서드만 선언할 수 있었으나 java 8 버전부터는 default, static, private 메서드도 선언할 수 있다. |
| 다중 상속을 지원하지 않는다. | 다중 상속을 지원한다. |
| final, non-final, static, non-static 변수를 가질 수 있다. | static 및 final variable만 가질 수 있다. |
| 인터페이스의 구현을 제공할 수 있다. | 추상 클래스의 구현을 제공할 수 없다. |
| abstract 키워드는 추상 클래스를 선언하는데 사용된다. | interface 키워드는 인터페이스를 선언하는데 사용된다. |
| 추상 클래스는 다른 클래스를 상속하고 여러 인터페이스를 구현할 수 있다. | 다른 인터페이스를 상속만 할 수 있다. |
Java 컴파일러는 내부 클래스의 경우 두 개의 클래스 파일을 생성하며, 내부 클래스를 인스턴스화 하려면 외부 클래스의 인스턴스를 만들어야 하며, 이 경우 외부 클래스의 인스턴스 내부에 내부 클래스의 인스턴스가 생성된다.
컴파일러는 Outer$Inner 형식의 클래스 파일을 생성하는데, 멤버 내부 클래스에는 Outer 클래스의 참조가 있으므로 Outer 클래스의 모든 데이터 멤버에 접근할 수 있다.
public class Outer1{
private int size;
/* Declare an inner class called "Inner" */
public class Inner{
public void doStuff(){
//The inner class has access to 'size' from Outer
size++;
}
}
public void testTheInner(){
Inner i = new Inner();
i.doStuff();
}
}
public class Outer2{
private int size;
public class Inner{
public void doStuff(){
size++;
}
}
}
public class TestInner{
public static void main(String[] args){
Outer2 outer = new Outer2();
//Must create an Inner object relative to an Outer
Outer2.Inner inner = outer.new Inner();
//반드시 종속되어 있는 클래스를 먼저 명시해 주어야 한다.
//Outer를 통해서만 Inner class에 접근할 수 있다.
inner.doStuff();
}
}
public class Outer3{
private int size;
public class Inner{
private int size;
public void doStuff(int size){
size++; //the local parameter
this.size++; //the Inner object attribute
Outer3.this.size++; //the Outer3 object attribute
}
}
}
public class Outer4{
private int size = 5;
public Object makeTheInner(int localVar){
final int finalLocalVar = 6;
//Declare a class within a method!
class Inner{
public String toString(){
return ("#<Inner size=" + size +
// " localVar=" + localVar + //ERROR: ILLEGAL
"finalLocalVar=" + finalLocalVar + ">");
}
}
return new Inner();
}
public static void main(String[] args){
Outer4 outer = new Outer4();
Object obj = outer.makeTheInner(47);
System.out.println("The object is " + obj);
}
}
[결과]
The Object is #<Inner size=5 finalLocalVar=6>
public abstract class MyInterface{
public abstract void doSomething();
}
//인터페이스 구현과 동시에 객체 생성
MyInterface myClass = new MyInterface(){
@Override
public void doSomething(){
System.out.println("doSomething");
}
};
myClass.doSomething();
public class LocalInnerEx1{
//인스턴스 멤버 변수
private int date = 30;
void display(){
class Local{
void msg(){
System.out.println(data);
}
}
Local l = new Local();
l.msg();
}
public static void main(String[] args){
LocalInnerEx1 obj = new LocalInnerEx1();
obj.display();
}
}
[결과]
30
public class StaticInnerEx1{
static int data=30;
static class Inner{
void msg(){System.out.println("data is "+data);}
}
public static void main(String[] args){
StaticInnerEx1.Inner obj = new StaticInnerEx1.Inner();
obj.msg();
}
}
[결과]
30