티스토리 뷰
자바 - 인터페이스 ( 상수 필드, 추상 메서드, 디폴트 메서드, 정적 메서드, private 메서드, 다중 인터페이스 )
Kodong's blog 2026. 3. 9. 21:14작년에 자바의 인터페이스에 대해서 정리한 적이 있다. ( 아래 포스팅들에서 정리했다. )
https://kodong8774.tistory.com/34
https://kodong8774.tistory.com/56
https://kodong8774.tistory.com/85
하지만, 글들을 보면 뭔가 제대로 이해하기 못한 상태로 적은 느낌이다. ( 실제로도 이해를 제대로 못했었다. )
그래서 이번 포스팅에서 확실하게 마무리를 하겠다.
물론 단순히 인터페이스는 어떻게 선언하는지 등과 같이 이미 알고 있는 내용은 생략하겠다.
-----------------------------------------------------------------------------------------------------------
🟩 인터페이스의 역할
아래와 같이, 객체A와 객체B가 있다고 하자.

이때, 인터페이스는 두 객체를 연결하는 역할을 한다.
그림과 같이 객체A는 인터페이스를 통해 객체 B를 사용할 수 있다.
객체 A가 인터페이스의 메서드를 호출하면, 인터페이스는 객체 B의 메소드를 호출하고, 그 결과를 받아 객체A에게 전달해준다.
객체A가 객체B의 메소드를 직접 호출하면 간단할텐데, 왜 중간에 인터페이스를 거치도록 하는 것일까?
다름 그림과 같이 객체B가 객체 C로 교체된다고 가정해보자.

객체A는 인터페이스의 메소드만을 사용하므로, 객체B가 객체C로 변경되는 것에 대해서는 관심이 없다.
만약 인터페이스 없이 객체A가 객체B를 사용한다면 객체A의 소스 코드를 객체 B에서 객체C로 변경하는 작업이 추가로 필요할 것이다.
이러한 인터페이스의 특징으로 인해, 상속을 이용해서 다형성을 구현할 수도 있지만, 인터페이스를 이용해서 다형성을 구현하는 경우가 더 많다고 한다.
인터페이스에는 아래와 같은 멤버들을 선언할 수 있다.
interface HelloInterface {
// public 상수 필드
// public 추상 메소드
// public 디폴트 메소드
// public 정적 메소드
// private 메소드
// private 정적 메소드
}
이제 각각 멤버에 대해서 알아보도록 하자.
🟩 상수 필드
인터페이스에 선언된 필드는 모두 public static final 특성을 갖기 때문에,
public static final을 생략하더라도 자동적으로 컴파일 과정에서 붙게 된다. (보통 생략한다.)
public static final <타입> <상수명> = <값>;
또, 상수명은 대문자로 작성하되, 서로 다른 단어로 구성되어 있을 경우에는 언더바(_)로 연결하는 것이 관례이다.
아래는 인터페이스에 MAX_VOLUME, MIN_VOLUME 상수를 선언한 예시이다. (public static final은 자동으로 컴파일 과정에서 붙게 된다!)
public interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
}
🟩 추상 메서드
인터페이스는 구현 클래스가 재정의해야하는 public 추상(abstract) 메소드를 멤버로 가질 수 있다.
당연하게도, 메서드 선언부만 기술되고, 중괄호는 붙이지 않는 메소드를 말한다.
이때 public abstract를 생략하더라도 컴파일 과정에서 자동으로 붙게 된다.
아래는 그 예시이다.
interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
void turnOn();
void turnOff();
void setVolume(int volume);
}
class Television implements RemoteControl {
private int volume;
@Override
public void turnOn() {
System.out.println("turn on TV");
}
@Override
public void turnOff() {
System.out.println("turn off TV");
}
@Override
public void setVolume(int volume) {
if (volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if (volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
}
}
}
그렇다. 뭔가 다형성이 보인다.
🟩 디폴트 메서드
인터페이스에서 추상 메서드와 디폴트 메서드의 차이점은 추상 메서드는 실행부(중괄호{})가 없지만, 디폴트 메서드는 실행부가 있다.
또 디폴트 메서드는 default 키워드가 리턴 타입 앞에 붙는다는 것이다.
public default <리턴타입> <메소드명>(<매개변수> ...) { ... }
(public 키워드를 생략하더라도 자동으로 컴파일 과정에서 붙게 된다.)
아래는 디폴트 메서드의 사용 예시이다.
interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
void turnOn();
void turnOff();
void setVolume(int volume);
default void setMute(boolean mute) {
if (mute) {
System.out.println("무음 처리");
setVolume(MIN_VOLUME);
} else {
System.out.println("무음 해제");
}
}
}
class Television implements RemoteControl {
private int volume;
@Override
public void turnOn() {
System.out.println("turn on TV");
}
@Override
public void turnOff() {
System.out.println("turn off TV");
}
@Override
public void setVolume(int volume) {
if (volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if (volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
}
System.out.println("현재 TV 볼륨 : " + this.volume);
}
}
class HelloInterface {
public static void main(String[] args) {
RemoteControl rc;
rc = new Television();
rc.turnOn();
rc.setVolume(5);
rc.setMute(true);
rc.setMute(false);
}
}
RemoteControl 인터페이스의 turnOn, turnOff, setVolume 기능은 구현체마다 다를 수 있으므로 추상 메서드로 선언했다. 하지만, setMute 메서드, 즉 무음 모드는 구현체에 동일하게 사용될 수 있으므로, 디폴트 메서드로 선언하였다.
물론 구현 클래스는 디폴트 메서드를 재정의해서 자신에게 맞게 수정할 수도 있다.
재정의 시 주의할 점은 public 접근 제한자를 반드시 붙여야하고, default 키워드를 생략해야한다.
@Override
public void setMute(boolean mute) {
// ...
}
🟩 정적 메서드, private 메서드
정적 메소드는 구현 객체가 없어도 인터페이스만으로 호출할 수 있다.
클래스 정적 메소드와 차이점이 있다면, public을 생략하더라도 자동으로 컴파일 과정에서 붙는다는 것이다.
[ public | private ] static <리턴타입> <메소드명>(<매개변수> ...) { ... }
private 메서드의 용도는 디폴트 메서드, 정적 메소드들의 중복 코드를 줄이기 위함이다.
아래는 두 메서드를 함께 사용한 예제이다.
interface Service {
// 디폴트 메서드
default void defaultMethod1() {
System.out.println("defaultMethod1 종속 코드");
defaultCommon();
}
default void defaultMethod2() {
System.out.println("defaultMethod2 종속 코드");
defaultCommon();
}
private void defaultCommon() {
System.out.println("defaultMethod 중복 코드A");
System.out.println("defaultMethod 중복 코드B");
}
// 정적 메서드
static void staticMethod1() {
System.out.println("staticMethod1 중복 코드");
staticCommon();
}
static void staticMethod2() {
System.out.println("staticMethod2 중복 코드");
staticCommon();
}
private static void staticCommon() {
System.out.println("staticMethod 중복 코드 C");
System.out.println("staticMethod 중복 코드 D");
}
}
class ServiceImpl implements Service {
}
class HelloInterface {
public static void main(String[] args) {
Service service = new ServiceImpl();
service.defaultMethod1();
service.defaultMethod2();
System.out.println();
Service.staticMethod2();
Service.staticMethod2();
}
}

🟩 다중 인터페이스 구현
구현 객체는 여러 개의 인터페이스를 implements할 수 있다.
이때 구현 객체는 implements한 모든 인터페이스의 추상 메소드를 재정의해야한다.
public class HelloWorld implements interfaceA, interfaceB {
// 모든 추상 메서드 재정의
}
또, 구현 객체가 어떤 인터페이스 변수에 대입되는냐에 따라서 변수를 통해 호출할 수 있는 추상 메소드가 결정된다.
인터페이스A 변수 = new 구현클래스명(...);
인터페이스B 변수 = new 구현클래스명(...);
🟩 인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있으며, 클래스와는 달리 다중 상속을 허용한다.
--------------------------------------------------------------------------------------------
※ 이 인터페이스 상속 부분은 정리를 해봤자 당장은 안 사용할 것같아서, 아직 정리를 하지는 않겠다.
※ 또 인터페이스에 대한 나머지 내용(타입 변환, 다형성, instanceof, 봉인된 인터페이스)는 이전 상속에 대해 정리한 포스팅 내용과 매우 유사하여 굳이 정리하지 않겠다.
'Java' 카테고리의 다른 글
| 자바 - 자바의 예외 구조, 예외 종류에 따른 처리, 예외 떠넘기기 (throws 키워드) (0) | 2026.03.16 |
|---|---|
| 자바 - (추후 내용 추가 및 수정 하자!) 중첩 선언과 익명 객체 (중첩 클래스, 중첩 인터페이스, 익명 객체) (0) | 2026.03.15 |
| 자바 - 상속 ( 클래스 상속, 메서드 오버라이딩, super, final 클래스 및 메서드의 상속, 자동/강제 타입 변환, 다형성, instanceof, 추상 클래스 ) (0) | 2026.03.08 |
| 자바 - 싱글톤 패턴(Singleton pattern) (0) | 2026.03.06 |
| 자바 - 생성자 오버로딩, this(), 가변길이 매개변수, 메서드 오버로딩, final 필드와 상수, 패키지 (0) | 2026.03.06 |