본문 바로가기
Language/java

Java_Study 객체지향 프로그래밍_인터페이스

by gamxong 2022. 7. 7.

 

인터페이스란?

 

: 일종의 추상클래스로, 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외 다른 어떠한 요소도 허용하지 않는다.

 

 

인터페이스의 작성

 

interface 인터페이스이름 {
	public static final 타입 상수이름 = 값;
	public abstract 메서드이름(매개변수목록);
}

 

- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.
   단, static메서드와 디폴트 메서드는 예외

 

 

 

인터페이스의 상속

 

인터페이스는 인터페이스로부터만 상속받을 수 있으며, 다중상속이 가능하다.

 

interface Movable {
	void move(int x, int y);
}

interface Attackable {
	void attack(Unit u);
}

interface Fightable extends Movable, Attackable { }

 

 

인터페이스의 구현

 

추상클래스처럼 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 함.

 

class 클래스이름 implements 인터페이스이름 {
	// 인터페이스에 정의된 추상메서드를 구현해야 한다.
}

class Fighter implements Fightable {
	public void moive(int x, int y) { /* 내용 생략 */ }
	public void attach(Unit u) { /* 내용 생략 */ }
}

 

 

class song_class {
	public static void main(String[] args) {
		Fighter f = new Fighter();
		
		if(f instanceof Unit) {
			System.out.println("f is unit 클래스 자손");
		}
		if(f instanceof Fightable) {
			System.out.println("f is fightable 클래스 자손");
		}
		if(f instanceof Movable) {
			System.out.println("f is moveable 클래스 자손");
		}
		if(f instanceof Attackable) {
			System.out.println("f is Attack 클래스 자손");
		}
		if(f instanceof Object) {
			System.out.println("f is object 클래스 자손");
		}
	}
}

class Fighter extends Unit implements Fightable {
	public void move(int x, int y) { /* 내용생략 */ }
	public void attack(Unit u) { /* 내용생략 */ }
}

class Unit {
	int currentHP;
	int x;
	int y;
}
interface Fightable extends Movable, Attackable { }
interface Movable { void move(int x, int y); }
interface Attackable { void attack(Unit u); }

 

클래스 인터페이스간의 관계

 

Movable 인터페이스에 void move(int x, int y)는 public abstract이 생략된 것.
따라서, Fighter 클래스에서는 void move(int x, int y)의 접근제어자를 반드시 public으로 해야 한다.
(자손 범위가 조상 범위보다 작지 않게 하기 위함)

 

 

 

인터페이스를 이용한 다중상속

 

주로 사용은 x

 

 

인터페이스를 이용한 다형성

 

- 인터페이스를 클래스의 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있음.

- 인터페이스 타입으로의 형변환도 가능

 

Fightable f = (Fightable) new Fighter();
// or
Fightable f = new Fighter();

 * 따라서 인터페이스는 다음과 같이 메서드의 매개변수의 타입으로 사용될 수 있다.

void attack(Fightable f) {
// ...
}

 

 - 인터페이스 타입의 매개변수가 갖는 의미는

    메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 한다는 것.

class Fighter extends Unit implements Fightable {
	public void move(int x, int y) { /* 내용 생략 */ }
	public void attack(Fightable f) { /* 내용 생략 */ }
}

 

 

Fightable method() {
	//...
    Fighter f = new Fighter();
    return f;
}
- 리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미.

 

 

interface Parseable {
	public abstract void parse(String fileName);
}

class ParserManager {
	public static Parseable getParser(String type) {
		if(type.equals("XML")) {
			return new XMLParser();
		} else {
			Parser p = new HTMLParser();
			return p;
		}
	}
}

class XMLParser implements Parseable {
	public void parse(String fileName) {
		System.out.println(fileName + "-XML");
	}
}

class HTMLParser implements Parseable {
	public void parse(String fileName) {
		System.out.println(fileName + "-HTML");
	}
}

class song_class {
	public static void main(String[] args) {
		Parseable parser = ParserManager.getParser("XML");
		parser.parse("docu.xml");
		parser=ParserManager.getParser("HTML");
		parser.parse("docu.html");
	}
}

 

 

 

인터페이스의 장점

 

  • 개발시간 단축
  • 표준화 가능
  • 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있음
  • 독립적인 프로그래밍이 가능

 

1. 개발시간 단축

   메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 된다.

   동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작동하도록 하여, 동시에 개발 가능

 

4. 독립적인 프로그래밍이 가능

   인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있어 독립적인 프로그래밍이 가능

 

 

interface Liftable {
    void liftoff();
    void move(int x, int y);
    void stop();
    void land();
}

class LiftableImpl implements Liftable {
    public void liftOff() { /* 내용생략 */ }
    public void move(int x, int y) { /* 내용생략 */ }
    public void stop() { /* 내용생략 */ }
    public void land() { /* 내용생략 */ }
}


class Barrack extends Building implements Liftable {
    LiftableImp 1 = new LiftableImp1();
    void liftOff() { 1.liftOff(); }
    void move(int x, int y) {1.move(x,y);}
    void stop() {1.stop();}
    void land() {1.land();}
    void trainMarine() { /* 내용생략 */ }
}

class Factory extends Building implements Liftable {
    LiftableImp 1 = new LiftableImp1();
    void liftOff() { 1.liftOff(); }
    void move(int x, int y) {1.move(x,y);}
    void stop() {1.stop();}
    void land() {1.land();}
    void trainMarine() { /* 내용생략 */ }
}

 

 

 

인터페이스의 이해

 

- 클래스를 사용하는 쪽과 클래스를 제공하는 쪽이 있다.
- 메서드를 사용하는 쪽에서는 사용하려는 메서드의 선언부만 알면 된다.

 

class A {
	public void methodA(B b) {
    	b.method();
    }
}

class B {
	public void methodB() {
    	System.out.println("methodB()");
        }
}

class InterfaceTest {
	public static void main(String args[]) {
    	A a = new A();
        a.methodA(new B());
    }
}

 

interface I {
	public abstract void methodB();
}

class A {
	public void methodA(I i) {
    	i.method();
    }
}

class B implements I {
	public void methodB() {
    	System.out.println("methodB()");
        }
}

class InterfaceTest {
	public static void main(String args[]) {
    	A a = new A();
        a.methodA(new B());
    }
}
'A-B' 직접적인 관계에서 'A-I-B'의 간접적인 관계로 바뀜.

 

 

class song_class {
	public static void main(String[] args) {
		A a = new A();
		a.methodA();
	}
}

class A {
	void methodA() {
		I i = InstanceManager.getInstance();
		i.methodB();
		System.out.println(i.toString());
	}
}

interface I {
	public abstract void methodB();
}

class B implements I {
	public void methodB() {
		System.out.println("method in B");
	}
	
	public String toString() { return "class B";}
}

class InstanceManager {
	public static I getInstance() {
		return new B();
	}
}

 

 - 인스턴스를 직접 생성하지 않고, getInstance() 라는 메서드를 통해 제공 받음

    -> 다른 클래스의 인스턴스로 변경되어도 A클래스의 변경없이 getInstance()만 변경하면 된다는 장점

 

- 인터페이스 I 타입의 참조변수 i로도 Object 클래스에 정의된 메서드들을 호출할 수 있음.

 

 

디폴트 메서드

 

interface MyInterface {
	void method();
    void newMethod(); // 추상메서드
}

///////////////////////////

interface MyInerface {
	void method();
    default void newmethod() { }    // 디폴트메서드
}
디폴트 메서드를 추가하면, 기존의 MyInterface를 구현한 클래스를 변경하지 않아도 된다.

 

 

* 디폴트 메서드가 충돌하는 경우

 

1. 여러 인터페이스의 디폴트 메서드 간의 충돌

  - 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 함

 

2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌

  - 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시됨

댓글