반응형
일종의 추상클래스로 추상화 정도가 높아서 추상클래스와 다르게 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다.
- 추상메서드와 상수만 멤버로 가질 수 있다. (다른 요소들 허용x)
- class 말고 interface로 사용되고 접근제어자는 public 또는 default만 사용가능하다.
interface 인터페이스이름 {
public static final 타입_상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
일반적인 클래스와 다르게 인터페이스 멤버들은 제약사항이 존재한다.
- 모든 멤버변수는 public static final 이어야 하며, 생략이 가능하다.
- 모든 메서드는 public abstract 이어야 하며, 생략이 가능하다.
- 단 static메서드와 default메서드는 예외(JDK1.8부터)
- 인터페이스의 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자 생략 가능
- 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.
interface playingCard {
public static final int SPADE = 4;
final int DIAMOND = 3; //public static final int DIAMOND = 3;
static int HEART = 2; //public static final int HEART = 2;
int CLOVER = 1; //public static final int CLOVER =1;
public abstract String getCardNumber();
String getCardKind(); //public abstract String getCardKind();
}
인터페이스 상속
인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와 다르게 다중상속이 가능하다.
- 인터페이스는 클래스와 달리 Object클래스와 같은 맨 상단의 부모가 없다.
인터페이스의 구현
인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없다.
- 인터페이스도 자신에 정의된 추상메서드의 몸통을 구현하는 클래스가 필요하다.
- 클래스는 확장한다는 의미의 ‘extends’를 사용했다.
- 인터페이스는 구현한다는 의미의 ‘implements’를 사용한다.
- 상속과 구현을 동시에 할 수 있다.
//구현
class 클래스이름 implements 인터페이스 이름 {
//인터페이스에 정의된 추상메서드를 모두 구현해야 한다.
}
//상속
interface 인터페이스 이름 extends 상속받을 인터페이스 이름1, 2... 다중상속 가능 {
}
//상속 + 구현
class 클래스이름 extends 클래스이름 implements 인터페이스명{
}
인터페이스의 메서드 중 일부만 구현한다면, abstract를 붙여서 추상클래스로 선언해야 된다.
인터페이스를 이용한 다형성
인터페이스 Fightable을 클래스 Fighter가 구현했을 때, Fighter인스턴스를 Fightable타입의 참조변수로 참조하는 것이 가능하다.
Fightable f = (Fightable)new Fighter();
또는
Fightable f = new Fighter();
//메서드의 매개변수 타입으로도 인터페이스를 사용할 수 있다.
void attack(Fightable f) {
//...
}
인터페이스 타입의 매개변수가 갖는 의미
- 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 한다.
- attack(new Fighter())와 같이 인스턴스 넘겨 줄 수 있다.
- 리턴타입으로 인터페이스를 지정하는 것도 가능하다.
Fightable method(){
...
return new Fighter();
}
- 리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
- return 문에서는 Fightable을 구현한 Fighter클래스의 인스턴스의 주소를 반환
인터페이스를 사용하는 이유와 장점
- 개발시간을 단축할 수 있다.
- 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문에, 동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하게 하면, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고 양쪽에서 동시에 개발이 가능하다.
- 표준화가 가능하다.
- 프로젝트 기본 틀을 인터페이스로 작성한 뒤, 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램 개발이 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.(서로 상속관계에 있지 않고, 같은 부모클래스를 가지고 있지 않은 관계없는 클래스들)
- 서로 관계없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
- 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경해 한클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않도록 프로그래밍 가능하다.
- 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램 작성이 가능하다.
default 메서드와 static 메서드
인터페이스에 추상메서드만 선언할 수 있는데 JDK1.8부터 default 메서드와 static 메서드도 추가할 수 있게 되었다.
- static 메서드는 인스턴스와 관계가 없는 독립적인 메서드기 때문에 처음부터 추가 가능했지만 규칙을 단순히 만들기 위해서 메서드는 추상메서드이어야 한다는 규칙에 예외를 두지 않았다.
- 부모 클래스에 새로운 메서드를 추가하는 것은 별 일 아니다. (부모클래스에 추가하면 자식클래스들이 그냥 사용하면 되니까)
- 인터페이스에 메서드를(추상 메서드) 추가한다는 것은, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 한다. → JDK의 설계자들이 default method를 만든 이유 중요!!!!
default method
추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 때문에 인터페이스에 default method가 추가되어도 해당 인터페이스를 구현한 클래스는 변경하지 않아도 된다.
- method명 앞에 default 붙이며 추상 메서드가 아니기 때문에 몸통 ‘{} ‘이 있어야 한다.
- default 메서드도 똑같이 접근제어자는 public이며 생략이 가능하다.
interface MyInterface{
void method(); //추상 메서드 public abstract void method();
default void newMethod(){} //디폴트 메서드 public default void newMethod(){}
}
새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생한다.
1. 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
2. 디폴트 메서드와 부모 클래스의 메서드 간의 충돌
- 부모 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
3. 잘 모르겠으면 필요한 쪽의 메서드와 같은 내용으로 오버라이딩 하기
class Child1 extends Parent1 implements MyInterface, MyInterface2{
@Override
public void method1() {
System.out.println("method1() int child1"); //오버라이딩 해야 한다.
}
}
class Parent1 {
public void method2(){
System.out.println("method2() in Parent1");
//default method 보다 우선 순위이기 때문에 오버라이딩 안해줘도 상관 없음
}
}
interface MyInterface {
default void method1(){
System.out.println("method1() in MyInterface");
}
default void method2(){
System.out.println("method2() int MyInterface");
}
static void staticMethod(){
System.out.println("staticMethod in MyInterface");
}
}
interface MyInterface2 {
default void method1(){
System.out.println("method1() in MyInterface2");
}
default void method2(){
System.out.println("method2() int MyInterface2");
}
static void staticMethod(){
System.out.println("staticMethod in MyInterface2");
}
}
//main
public static void main(String[] args) {
Child1 child1 = new Child1();
child1.method1();
child1.method2();
MyInterface.staticMethod();
MyInterface2.staticMethod();
}
/* 출력
method1() int child1
method2() in Parent1
staticMethod in MyInterface
staticMethod in MyInterface2
*/
반응형
'책 > Java의 정석' 카테고리의 다른 글
[java] instanceof 연산자 (0) | 2023.02.07 |
---|---|
[java] 내부 클래스(inner class)와 익명 클래스(anonymous class) (0) | 2023.02.04 |
[java] 추상클래스와 추상메서드 (0) | 2023.02.04 |
[java] 제어자(modifier) (2) | 2023.02.04 |
[java] import문 (0) | 2023.02.04 |