Class에 대해 배우면서 Class가 object(객체)를 만들기 위한 템플릿이라는 것을 알 수 있었습니다.
그런데 이러한 class를 만들기 위해 존재하는 템플릿도 있는데요, 그것이 바로 interface(인터페이스)입니다.
사실 interface는 inheritacne(상속)의 한계를 극복하고자 등장한 개념이라고 합니다. 상속의 한계에는 뭐가 있었을까요?
바로 하나의 class만 상속이 가능하다는 점이 있었습니다! (그런 한계 때문에 composition 사용을 장려한다고도 했었죠.)
하지만 사람들은 그래도 여러 클래스의 기능들을 불러와서 사용하고 싶었나 봅니다. 아마도 동일한 코드를 반복하여 작성하지 않기 위해서겠죠? 그래서 interface라는 개념이 등장하게 되었습니다.
Class를 상속할 때는 extends 라는 키워드를 사용했는데, interface를 사용하려면 implements 키워드를 사용합니다.
실제로 interface는 한개 이상 implements가 가능합니다. 한 번 예시로 살펴보겠습니다.
//IInterface1과 IInterface2 둘 다 implements 한 상태
public class TestClass implements IInterface1, IInterface2{}
public interface IInterface1 {}
public interface IInterface2 {}
보시다시피 TestClass는 두 개의 인터페이스를 한 번에 implements 하고 있습니다. 상속에서는 불가능했었는데 말입니다.
IInterface1과 IInterface2 처럼 "interface"라는 keyword로 interface를 정의할 수 있습니다.
Interface는 어떻게 생겼는지 형태를 한 번 살펴보면, 아래와 같습니다.
public interface IInterface1 {
//method는 바디를 가질 수 없으며 ({}안의 내용)
//public abstract 입니다. (static, default도 가능)
public abstract void method1();
//field는 pulic static final이어야 합니다.
public static final int myVariable = 10;
}
1) Method의 경우, public abstract가 기본적인 조건입니다. 기본값이기 때문에 해당 부분은 생략하고 void method1(); 과 같이 선언해도 무방합니다. 독특한 점은 method의 이름만 있고 내용물이 없다는 점인데요, abstract method(추상 메서드)이기 때문입니다.
그렇기 때문에 methods가 있는 interface를 implements하는 class는 반드시 interface의 methods를 override해야만 합니다.
2) Variable의 경우 public static final(constant)이 기본 조건입니다. 역시나 해당 부분은 생략하여도 compile 시에 자동적으로 추가가 됩니다.
형태가 굉장히 간결해서 생소하지만 그 만큼 자유롭게 쓰일 수 있을 것 같은 느낌이 듭니다!
(+ Interface들 간에도 상속이 가능한데요, 특이하게도 다중 상속이 가능합니다.
public interface IInterface3 extends IInterface1, IInterface2{
}
IInterface3는 IInterface1과 IInterface2를 implements하고 있기 때문에, 두 인터페이스로부터 상속받은 추상 메서드를 멤버로 가지게 됩니다. )
위에서 인터페이스가 다중상속을 위한 대체재로 나왔다고는 했지만, 실제로는 다중 상속의 용도 보다는 개발 시간을 단축하고 서로 연결되어 있는 클래스에 변동사항이 생기더라도 코드 수정을 최소화 하기 위한 용도로 많이 쓰인다고 합니다. 어떻게 그게 가능한지 차근차근 알아보겠습니다.
먼저 기본적인 형태를 한 번 살펴볼까요?
예를 들어서, Animal이라는 class를 상속하는 Dog, Cat, Bird, Fish 라는 4개의 클래스가 있다고 가정해보겠습니다.
public class Animal {
public void move() {
System.out.println("움직인다");
}
}
public class Dog extends Animal{
}
public class Cat extends Animal{
}
public class Bird extends Animal{
}
public class Fish extends Animal{
}
Dog, Cat, Bird, Fish 모두 부모 클래스인 Animal의 method인 move()를 사용할 수 있습니다.
만약에 Bird와 Fish에만 layEggs()라는 method를 추가하고 싶다면 어떻게 하면 될까요? 만약에 Animal class에 추가하게 되면, layEggs()와 상관없는 Dog와 Cat class에도 적용이 되므로 좋은 방법이 아닐겁니다. 이럴 때에 interface를 사용하면 효과적으로 원하는 효과를 이룰 수 있습니다.
public interface ILayEggs {
void layEggs();
}
//ILayEggs interface를 Bird와 Fish에 implements 해줍니다.
public class Bird extends Animal implements ILayEggs{
@Override
public void layEggs() {
System.out.println("새가 둥지에 알을 낳는다.");
}
}
public class Fish extends Animal implements ILayEggs{
@Override
public void layEggs() {
System.out.println("물고기가 바위 사이에 알을 낳는다.");
}
}
이렇게 인터페이스를 생성해주고 그 안에 method를 만들어 줍니다. 그런 다음에 Bird와 Fish가 해당 인터페이스를 implements하게 하면 됩니다! 그러면 두 클래스만 layEggs()에 접근할 수 있고, Dog와 Cat은 접근할 수 없게됩니다.
물론, Bird와 Fish 각각 layEggs() 라는 method를 선언해주어도 되지만, 그렇게 되면 동일한 코드를 작성하게 되므로 효율성이 떨어지게 되겠죠?
이런식으로 interface는 단일 상속의 한계를 보완해주면서 코드 활용성을 높여준다는 것을 보았습니다.
글이 조금 길어질 것 같아서 다음번에 이어서 어떻게 사용하는지 조금 더 구체적인 내용과 코드 수정이 일어났을 때의 강점에 대해 알아보겠습니다.
감사합니다 ☺️
*참고로 nested interface는 명시하지 않아도 static이다!
'Java' 카테고리의 다른 글
Inner class - local class (0) | 2022.05.09 |
---|---|
Inner class 알아보기 (0) | 2022.05.09 |
Autoboxing & Unboxing (2) | 2022.05.05 |
Array-배열 (0) | 2022.05.02 |
Class(7)-Up-casting & Down-casting (형변환 업캐스팅, 다운캐스팅) (2) | 2022.05.01 |