인터페이스(interface)
- 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다.
- 구현된 것은 아무 것도 없고 밑그림만 그려져 있는 기본 설계도라 할 수 있다. 인터페이스도 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움 줄 목적으로 작성된다.
인터페이스의 작성
- 문법
interface 인터페이스명{
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수 목록);
}
접근제어자로 public, default를 사용할 수 있다.
- 제약사항
모든 멤버변수는 public static final이어야 하며, 이를 생략할 수 있다.
모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있다.
[참고] 인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자가 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.
인터페이스의 상속
- 인터페이스는 인터페이스로부터만 상속(extends)받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다. 클래스와 마찬가지로 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속받는다.
인터페이스의 구현
- 인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야하는데, 그 방법은 추상클래스와 다르지 않다. 다만, 클래스는 확장한다는 의미의 'extends'를 사용하지만 인터페이스는 구현한다는 의미의 'implements'를 사용한다.
- 만일 구현하는 인터페이스의 메서드 중 일부만 구현한다면, 추상클래스로 선언되어야 한다.
- 인터페이스는 상속 대신 구현이라는 용어를 사용하지만, 인터페이스로부터 상속받은 추상메서드를 구현하는 것이기 때문에 인터페이스도 조금은 다른 의미의 조상이라고 할 수 있다.
인터페이스를 이용한 다중상속
- 두 조상으로부터 상속받을때 두 조상의 멤버들이 동일하여 어느 조상의 멤버를 상속받게되는 것인지 알 수 없게 될때, 어느 한 쪽으로부터 상속을 포기하던가, 이름이 충돌하지 않도록 조상클래스를 변경하는 수 밖에 없다. 이러한 이유로 자바에서는 다중상속을 허용하지 않는데 C++에서는 다중상속을 허용하기 때문에 이에 대한 대응으로 인터페이스를 사용하여 다중상속이 가능하게 하였다. 그러나 실제로 다중상속만을 위해서 인터페이스를 사용하지는 않는다.
인터페이스를 이용한 다형성
- 인터페이스도 다형성이 가능하다. 인터페이스를 구현한 클래스의 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다.
- 인터페이스는 메서드의 매개변수의 타입으로 사용될 수 있다. 즉 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야한다.
interface Fruits{}
class Apple implements Fruits{}
class Strawberry implements Fruits{}
class Orange implements Fruits{}
class Watermelon{} // Fruits implements 하지 않은 클래스!
// 매개변수와 리턴타입으로도 가능하다는걸 보여주는 Deal 클래스이다.
class Deal{
Fruits fruits; // 상속 복습. has a 관계.
Deal(){} // 기본 생성자
Deal(Fruits fruits){
this.fruits = fruits;
}
void buy(Fruits f){ // 매개변수로 인터페이스 사용
System.out.println(f+"를 샀습니다.");
}
Fruits getFruits(){ // 리턴타입으로 지정하는 것도 가능하다.
return fruits;
}
}
public class Test {
public static void main(String[] args) {
/*
* Apple, Strawberry, Orange는 Fruits를 상속받은 클래스이기 때문에 이 클래스들의 인스턴스들은 Fruits 타입의 참조변수에 대입될 수 있다.
* 자식 클래스의 인스턴스는 별도의 캐스팅 없이 프로모션 된다.
*/
Fruits fruits1 = new Apple();
Fruits fruits2 = new Strawberry();
Fruits fruits3 = new Orange(); // promotion
Deal dealer = new Deal();
dealer.buy(fruits1); // Fruits타입의 fruits1은 매개변수로 가능하다.
Strawberry strawberry = (Strawberry)fruits2; // casting
dealer.buy(strawberry); // Strawberry타입의 strawberry도 매개변수로 가능하다. 결국은 이것도 promotion
Watermelon watermelon = new Watermelon();
/*
* Watermelon은 Fruits를 구현하지 않았기 때문에 Fruits 속성을 가지고 있지 않다.
* 따라서 메서드의 파라미터 값에 해당하지 않으므로 에러가 난다.
*/
dealer.buy(watermelon); // error msg : The method buy(Fruits) in the type Deal is not applicable for the arguments (Watermelon)
Deal dealer2 = new Deal(fruits3);
System.out.println(dealer2.getFruits());
}
}
- 만약 인터페이스의 다형성이 없다면 위의 buy(Fruits)메서드는 각 과일의 타입마다 오버로딩 해주어야 할것이다.(buy(Apple), buy(Strawberry), buy(Orange) 등...) 하지만 인터페이스의 다형성으로 인해 프로그래밍의 중복을 줄여주고 사용자의 사용도 간단해졌다.
interface Unit{}
interface Fightable{}
class GroundUnit implements Unit{} // 인터페이스는 implements를 사용하여 구현한다.
class AirUnit implements Unit{}
class Marin extends GroundUnit implements Fightable{} // 상속과 구현이 동시에 가능하다.
class firebat implements Unit, Fightable{} // 다중상속이 가능하다.
class overload extends AirUnit{}
추상화 <-> 구체화
오른쪽에 위치한 클래스들의 인스턴스를 왼쪽에 위치한 클래스의 타입으로 참조하는것은 가능하다. 하지만 그 반대는 불가능하다.
- Unit
- Fightable
- Unit - GroundUnit // GroundUnit은 GroundUnit와 Unit타입 두가지를 가진다.
- Unit - AirUnit
- Unit - GroundUnit - Marin // Marin은 총 세가지의 타입을 가진다.
Fightable ---------┘
- Unit - firebat
Fightable ┘
- Unit - AirUnit - overload
인터페이스의 장점
- 개발시간을 단축시킬 수 있다.
인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문이다. 그리고 동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하도록 하여, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.
- 표준화가 가능하다.
프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 개발이 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다. 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.
[참고] 자세한 설명은 여기(새창| 강의필기 0903일 장점부분) 참고
인터페이스의 이해
- 클래스를 사용하는 쪽(user)과 클래스를 제공하는 쪽(provider)이 있다.
- 메서드를 사용(호출)하는 쪽(user)에서는 사용하려는 메서드(provider)의 선언부만 알면 된다.(내용은 몰라도 된다.)
[참고] 자세한 설명은 여기(새창| 강의필기 0903일 간접적인 관계)참고
'예전 포스팅 모음' 카테고리의 다른 글
[DB] 테이블 생성 및 crud sql문 예제 (0) | 2014.09.19 |
---|---|
[DB] Transaction, Select, update, delete, truncate (0) | 2014.09.19 |
[java] 추상클래스(abstract class) (0) | 2014.09.18 |
[DB] 오라클 구조, sqlplus.exe 사용법, 테이블 생성, 레코드 추가 (0) | 2014.09.18 |
[DB] RDBMS(Relationship Database management System, 관계형 데이터베이스)란? (0) | 2014.09.18 |