인터페이스(Interface)란 ?
자바에서 인터페이스(Interface) 는 해야 할 작업의 구체적인 구현 없이 기능만을 선언한 클래스이다. 즉, 자바의 인터페이스는 하위 클래스가 수행해야 하는 메소드와 필요한 상수만을 미리 추상적으로 정의해 놓은 클래스이다. 자바의 일반 클래스는 다중상속을 지원하지 않는다. 그러나 인터페이스의 경우 추상 클래스보다 더 추상적인 클래스로 여러 인터페이스를 상속받는 다중 상속을 지원한다!!
인터페이스와 구현 클래스 선언
앞에서 말했듯이 인터페이스는 '.java' 형태의 소스 파일로 작성되고 '.class' 형태로 컴파일 되기 때문에 물리적 형태는 클래스와 동일하다. 인터페이스의 구현에서는 class 대신 키워드 interface를 사용하며, 구현 없이 기능만 정의되는 메소드는 public abstract 의 추상 메소드로만 정의되어야 한다. 만약 abstract 가 선언되지 않아도, interface 로 작성되어지면 public abstract 는 생략된 것으로 간주된다. 멤버변수의 정의 또한 static final 이어야 하며, 메소드와 동일하게 이를 생략하여 사용할 수 있다.
(참고 : 인터페이스의 모든 메서드는 추상메서드이어야 하지만 JDK1.8 부터는 static method 와 default method 의 추가를 허용하는 방향으로 변경되었다.)
intellij 에서 interface 를 선언하였을때 메소드를 정의하는 public abstract 와 멤버변수를 정의하는 public static final 이 회색으로 음영처리 되어있는 것을 볼 수 있는데, 이것은 생략 가능함을 의미한다.
인터페이스 구현
인터페이스 또한 추상클래스처럼 그 자체로는 인스턴스 생성이 불가능하다. 추상 클래스가 상속을 통해 완성되는 것처럼 인터페이스도 구현부를 만들어주는 클래스에 구현(상속) 되어야 한다. 인터페이스의 구현은 implements 키워드를 사용하면 된다. 만약 인터페이스를 상속 받았다면, 자식 클래스에서 인터페이스가 포함하고 있는 추상 메소드를 구체적으로 구현해준다.
해당 코드는 Animal 인터페이스가 makeSound 메소드를 정의하고 있으며, Dog 와 Cat 클래스는 이 인터페이스를 단일로 구현한다. 각 클래스는 makeSound 메소드를 자신만의 방식으로 구현하여 동물의 소리를 타나낸다. 인터페이스의 가장 큰 특징은 다중 상속이 가능한데 이를 구현하는 예제 코드는 아래와 같다.
해당 코드는 Animal 과 Employee 인터페이스를 다중상속하여 Zoo 라는 클래스를 선언하였고 Zoo 클래스는 Animal 이 가진 makeSound 와 Employee 가 가진 work 메서드를 모두 구현해야 한다. 따라서 main 에서의 결과는 다음과 같다.
인터페이스를 구현받고 추상 메서드를 구체적으로 구현할 때 접근제어자 설정에 주의해야 한다. 기본적으로 메서드를 오버라이딩 할때는 부모의 메서드 보다 넓은 범위의 접근제어자를 지정해야 한다는 규칙이 존재한다. 따라서 인터페이스의 추상 메소드는 기본적으로 public abstract 가 생략된 상태이기 때문에 반드시 자식 클래스의 메서드 구현부에서는 제어자를 public 으로 설정해주어야 한다.
인터페이스 자체 상속
클래스 끼리 상속을 통해 확장하듯이, 인터페이스 자체를 확장 시키고 싶다면 extends 를 통해 인터페이스를 상속하면 된다. 클래스와 달리 인터페이스 끼리의 상속은 다중 상속이 가능하다.(메소드 구현부가 없기 때문에 충돌 가능성이 없다.) 클래스의 상속과 마찬가지로 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속 받는다. 아래의 예제 코드에서는 에버랜드라는 인터페이스가 동물과 직원을 하나의 인터페이스로 통합 상속 받는다. 그 후에 삼성 클래스는 통합된 인터페이스인 에버랜드를 그대로 상속 받는다. 따라서 메인함수에서 makeSound를 출력시키면 "푸바우가 소리를낸다." 의 값을 얻을 수 있을 것이고 work를 출력 시키면 "사육사가 푸바우를 씻겨준다." 라는 값을 얻을 수 있다.
default 메서드와 static 메서드
Java 1.8에서 부터는 인터페이스에 default 메서드와 static 메서드가 추가되었다. 이 두 종류의 메서드는 인터페이스를 더 유연하게 만들어 주며, 기존 코드를 변경하기 않고도 새 기능을 인터페이스에 추가할 수 있는 방법을 제공한다. 한마디로 수백 수십개가 이미 구현되어 있는 인터페이스에서 한가지 기능을 추가하기 위해 추상 메서드를 추가하게 된다면 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 하기 때문에 굉장히 곤란한 상황이 생기는데 이를 해결하기 위함인 것이다. 인터페이스의 변경이 없는것이 가장 좋은 방법이지만 언젠간 설계가 변경되어야 하는 경우가 생기기 때문에 이때 default 메서드 또는 static 메서드를 사용하면 된다.
Default 메서드 | Static 메서드 |
인터페이스에 구현 코드가 포함되어 있는 메서드이다. 이 메서드는 인터페이스를 구현하는 클래스에 자동으로 상속되며, 필요에 따라 오버라이드가 가능하다. 기존의 인터페이스를 확장하면서도, 이 인터헤이스를 이미 사용하고 있는 기존 코드를 깨뜨리지 않는 방식으로 새 기능을 추가할 수 있게 해준다. | 인터페이스에 속하지만 인스턴스에 대한 참조 없이 인터페이스 이름으로 직접 호출할 수 있는 메서드이다. 유틸리티 함수나 인터페이스와 관련된 도우미 메서드를 제공하는데 사용 될 수 있다. 인터페이스의 static 메서드는 인터페이스를 구현하는 클래스에 상속되지 않는다. |
위의 코드에서 Employee 인터페이스에 각각 static 과 default 메서드를 추가해주었다. static 메서드는 인터페이스 이름을 통해 직접 호출 할 수 있으며, default 메서드는 인터페이스를 구현하는 클래스의 인서턴스를 통해 호출 할 수 있다.
일반 클래스와 인터페이스 간의 차이점을 표로 정리하자면 이렇게 된다.
기준 | 클래스(Class) | 인터페이스(Interface) |
목적 | 객체의 구체적인 구현을 정의 | 특정 기능을 구현하기 위한 메서드의 시그니처 정의 |
인스턴스화 | 가능 (객체 생성 가능) | 불가능 (단독으로 객체 생성 불가) |
구현 방법 | 클래스 내부에서 메서드 구현 | 클래스가 인터페이스를 구현할 때 메서드 구현 |
상속 및 구현 | 다른 클래스를 상속할 수 있음(단일 상속) | 여러 인터페이스를 구현할 수 있음 |
변수 | 인스턴스 변수 및 클래스 변수 포함 가능 | 상수만 포함 가능(public static final) |
메서드 | 구체적인 구현 메서드 및 추상 메서드 포함 가능 | 모든 메서더는 기본적으로 추상메서드 |
접근제어자 | public, protected, private, default | 메서드와 변수는 기본적으로 public |
생성자 | 생성자를 가질 수 있음 | 생성자를 가질 수 없음 |
다중상속 | 지원하지 않음 | 인터페이스는 다중 구현을 지원 |
'Java' 카테고리의 다른 글
[Java] 예외(Exception) (0) | 2024.05.09 |
---|---|
[Java] 내부 클래스(Inner class) (0) | 2024.05.01 |
[Java] 추상화(Abstract) (2) | 2024.04.28 |
[Java] 다형성 (Polymorphism) (0) | 2024.04.26 |
[Java] 오버로딩 & 오버라이딩(Overloading & Overriding) (0) | 2024.04.09 |