1. 인터페이스란?
자바에서 인터페이스는 클래스가 구현해야 하는 메서드의 규격(계약)을 정의하는 역할을 합니다. 즉, 행동의 청사진(스펙)을 제공하며, 인터페이스에 선언된 메서드들을 해당 인터페이스를 구현하는 클래스가 반드시 구현해야 합니다.
인터페이스는 자바의 다형성(Polymorphism)을 지원하는 중요한 개념 중 하나로, 이를 통해 서로 다른 클래스들이 동일한 방식으로 호출될 수 있도록 보장합니다.
2. 인터페이스의 특징
2.1 메서드 선언만 존재 (자동으로 public abstract
적용)
인터페이스 내의 메서드는 구현부가 없는 추상적인 메서드입니다. 별도로 public
또는 abstract
를 명시하지 않아도, 모든 인터페이스 메서드는 자동으로 public
과 abstract
가 적용됩니다. 즉, 인터페이스의 모든 메서드는 기본적으로 public abstract
메서드입니다.
구현 클래스는 이 메서드들을 반드시 public
으로 구현해야 합니다. 만약 public
을 생략하거나 다른 접근 제어자를 사용할 경우 컴파일 오류가 발생합니다.
interface MyInterface {
// 컴파일러가 자동으로 'public abstract'를 추가
void someMethod();
}
class MyClass implements MyInterface {
// 반드시 public으로 구현해야 함
@Override
public void someMethod() {
System.out.println("MyClass에서 someMethod를 구현했습니다.");
}
}
public class Main {
public static void main(String[] args) {
MyInterface obj = new MyClass();
obj.someMethod(); // "MyClass에서 someMethod를 구현했습니다." 출력
}
}
- 인터페이스에서 선언된 메서드는
public abstract
로 자동 처리되므로, 이를 구현하는 클래스에서 반드시public
으로 구현해야 합니다. MyInterface
의someMethod()
는 구현부가 없는 추상 메서드이며,MyClass
에서 이를public
으로 구현하여 호출할 수 있습니다.- 만약
public
을 생략하거나private
또는protected
로 구현하면, 컴파일 오류가 발생하게 됩니다.
// 오류 발생 코드 예시
class MyClass implements MyInterface {
// public을 생략하면 컴파일 오류 발생
// Error: attempting to assign weaker access privileges; was public
void someMethod() {
System.out.println("MyClass에서 someMethod를 구현했습니다.");
}
}
2.2 다중 구현 가능
자바는 다중 상속을 허용하지 않지만, 인터페이스는 여러 개를 다중 구현할 수 있습니다. 이를 통해 클래스는 여러 동작 방식을 자유롭게 결합할 수 있습니다.
interface InterfaceA {
void methodA();
}
interface InterfaceB {
void methodB();
}
class MyClass implements InterfaceA, InterfaceB {
@Override
public void methodA() {
System.out.println("InterfaceA의 methodA 구현");
}
@Override
public void methodB() {
System.out.println("InterfaceB의 methodB 구현");
}
}
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.methodA(); // "InterfaceA의 methodA 구현" 출력
myClass.methodB(); // "InterfaceB의 methodB 구현" 출력
}
}
2.3 필드 선언
인터페이스에서는 필드를 선언할 수 있지만, 이 필드는 자동으로 public
, static
, final
로 선언됩니다. 즉, 인터페이스 내의 필드는 상수로 취급되며 변경할 수 없습니다.
interface MyInterface {
// public static final int CONSTANT = 100;
int CONSTANT = 100; // public static final 생략됨 (위와 같은 표현)
}
class MyClass implements MyInterface {
public void printConstant() {
System.out.println("CONSTANT 값: " + CONSTANT);
}
}
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.printConstant(); // "CONSTANT 값: 100" 출력
}
}
2.4 인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있습니다. 인터페이스끼리 상속할 때는 extends
키워드를 사용합니다.
interface ParentInterface {
void parentMethod();
}
interface ChildInterface extends ParentInterface {
void childMethod();
}
class MyClass implements ChildInterface {
@Override
public void parentMethod() {
System.out.println("ParentInterface의 parentMethod 구현");
}
@Override
public void childMethod() {
System.out.println("ChildInterface의 childMethod 구현");
}
}
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.parentMethod(); // "ParentInterface의 parentMethod 구현" 출력
myClass.childMethod(); // "ChildInterface의 childMethod 구현" 출력
}
}
2.5 자바 8 이후의 추가 기능
default
메서드: 인터페이스에서 기본 동작을 구현할 수 있는 메서드로,default
키워드로 정의됩니다. 이 메서드는 인터페이스를 구현하는 클래스에서 필요에 따라 오버라이딩 가능합니다.
interface MyInterface {
default void defaultMethod() {
System.out.println("인터페이스에서 제공하는 기본 구현");
}
}
class MyClass implements MyInterface {
@Override
public void defaultMethod() {
System.out.println("MyClass에서 defaultMethod를 재정의");
}
}
public class Main {
public static void main(String[] args) {
MyInterface obj1 = new MyClass();
obj1.defaultMethod(); // "MyClass에서 defaultMethod를 재정의" 출력
MyInterface obj2 = new MyInterface() {}; // 익명 구현 클래스
obj2.defaultMethod(); // "인터페이스에서 제공하는 기본 구현" 출력
}
}
static
메서드: 인터페이스 내에서static
메서드를 정의할 수 있습니다. 이는 인터페이스 자체에서만 호출 가능하며, 구현 클래스에서는 오버라이딩할 수 없습니다.
interface MyInterface {
static void staticMethod() {
System.out.println("인터페이스의 static 메서드");
}
}
class MyClass implements MyInterface {
// static 메서드는 오버라이딩 불가
// @Override
// public static void staticMethod() { } // 컴파일 에러 발생
}
public class Main {
public static void main(String[] args) {
MyInterface.staticMethod(); // "인터페이스의 static 메서드" 출력
}
}
3. 인터페이스의 사용 목적
3.1 다형성 구현
인터페이스를 사용하면 여러 클래스가 동일한 방식으로 호출될 수 있게 하여 다형성을 구현할 수 있습니다. 예를 들어, 다양한 동물을 모델링하는 클래스들이 각각 인터페이스 Animal
을 구현하면, Animal
타입으로 각각의 동물들을 동일하게 다룰 수 있습니다.
interface Animal {
void sound();
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("멍멍");
}
}
class Cat implements Animal {
@Override
public void sound() {
System.out.println("야옹");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
dog.sound(); // "멍멍" 출력
cat.sound(); // "야옹" 출력
}
}
3.2 코드의 확장성 및 유지보수성 향상
인터페이스를 사용하면 구현체가 변경되더라도 그 변경이 외부에 영향을 미치지 않으므로, 시스템의 유연성과 유지보수성이 향상됩니다. 예를 들어, 데이터베이스 연결을 위한 인터페이스를 정의해 두면, 나중에 구현체가 MySQL에서 PostgreSQL로 변경되더라도 인터페이스는 그대로 유지됩니다.
interface DatabaseConnector {
void connect();
}
class MySQLConnector implements DatabaseConnector {
@Override
public void connect() {
System.out.println("MySQL 데이터베이스에 연결합니다.");
}
}
class PostgreSQLConnector implements DatabaseConnector {
@Override
public void connect() {
System.out.println("PostgreSQL 데이터베이스에 연결합니다.");
}
}
public class Main {
public static void main(String[] args) {
DatabaseConnector db = new MySQLConnector();
db.connect(); // "MySQL 데이터베이스에 연결합니다." 출력
db = new PostgreSQLConnector();
db.connect(); // "PostgreSQL 데이터베이스에 연결합니다." 출력
}
}
3.3 구현 강제
인터페이스는 클래스가 반드시 구현해야 할 메서드들을 강제합니다. 이를 통해 일관된 행동을 보장하고, 여러 클래스가 동일한 규격을 따르도록 할 수 있습니다.
interface Vehicle {
void move();
}
class Car implements Vehicle {
@Override
public void move() {
System.out.println("자동차가 움직입니다.");
}
}
class Bicycle implements Vehicle {
@Override
public void move() {
System.out.println("자전거가 움직입니다.");
}
}
public class Main {
public static void main(String[] args) {
Vehicle car = new Car();
car.move(); // "자동차가 움직입니다." 출력
Vehicle bicycle = new Bicycle();
bicycle.move(); // "자전거가 움직입니다." 출력
}
}
4. 인터페이스와 추상 클래스의 차이점
- 추상 클래스는 단일 상속만 허용하지만, 인터페이스는 다중 구현이 가능합니다.
- 추상 클래스는 상태(필드)를 가질 수 있지만, 인터페이스는 상수만을 가질 수 있습니다.
- 추상 클래스는 추상 메서드와 일반 메서드를 가질 수 있지만, 인터페이스는 기본적으로 메서드 구현이 없고(자바 8부터
default
와static
메서드가 추가되었음), 모든 메서드는 기본적으로 추상적입니다.
특징 | 인터페이스 | 추상 클래스 |
---|---|---|
다중 상속 | 가능 | 불가능 |
상태(필드) | public static final 필드만 허용 |
일반 필드 허용 |
메서드 구현 여부 | default 메서드를 제외하고 구현 없음 |
추상 메서드와 일반 메서드 모두 가능 |
구현 강제 | 구현 클래스가 모든 메서드를 구현해야 함 | 추상 메서드만 구현 강제 |
5. 결론
인터페이스는 자바에서 객체지향 프로그래밍을 구현하는 중요한 개념입니다. 인터페이스를 통해 클래스는 행동의 규격을 정의하고, 그 규격을 따르는 여러 클래스를 설계할 수 있습니다. 이로 인해 다형성을 효과적으로 활용하여 다양한 객체를 동일한 방식으로 다룰 수 있으며, 코드의 유연성과 확장성을 크게 높일 수 있습니다.
인터페이스는 또한 코드의 유지보수성을 향상시키는 도구입니다. 시스템의 구현체가 변경되더라도, 외부에서 사용하는 인터페이스는 일관된 방식을 유지함으로써 코드를 재사용하기 쉽게 하고, 큰 변경 없이 새로운 기능을 추가할 수 있게 해줍니다.
자바 8 이후로 추가된 default
메서드와 static
메서드는 인터페이스의 기능을 더욱 확장시켜 기본 구현을 제공하거나, 인터페이스 자체에서 메서드를 호출할 수 있게 하여 개발자의 선택의 폭을 넓혔습니다.
또한 인터페이스와 추상 클래스는 비슷하지만 명확한 차이가 있습니다. 특히 다중 상속이 필요한 경우, 인터페이스를 통해 여러 동작을 결합할 수 있는 장점이 있습니다.
결론적으로, 인터페이스를 효과적으로 활용하면 자바 프로그램에서 구조적이고 유연한 설계를 가능하게 하며, 대규모 시스템의 유지보수와 확장성에 기여할 수 있습니다. 인터페이스는 올바르게 사용된다면, 객체 지향 설계 원칙을 잘 따르면서도 유지보수성이 뛰어난 코드를 작성할 수 있는 강력한 도구입니다.
'BackEnd > JAVA' 카테고리의 다른 글
[JAVA] try-with-resources 정리 (0) | 2025.01.19 |
---|---|
[JAVA] 자바 부모클래스 및 인터페이스 심화: 오버라이딩과 메서드 동작 (0) | 2025.01.17 |
[JAVA] 추상 클래스 (Abstract Class) 정리 (0) | 2025.01.09 |
[JAVA] 접근 지정자 (Access Modifiers) 정리 (0) | 2025.01.06 |
[JAVA] 자바에서 main 메서드가 static인 이유 (0) | 2025.01.06 |