[JAVA] 인터페이스 정리

2025. 1. 12. 23:21·BackEnd/JAVA

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 정리  (1) 2025.01.19
[JAVA] 자바 부모클래스 및 인터페이스 심화: 오버라이딩과 메서드 동작  (1) 2025.01.17
[JAVA] 추상 클래스 (Abstract Class) 정리  (0) 2025.01.09
[JAVA] 접근 지정자 (Access Modifiers) 정리  (1) 2025.01.06
[JAVA] 자바에서 main 메서드가 static인 이유  (0) 2025.01.06
'BackEnd/JAVA' 카테고리의 다른 글
  • [JAVA] try-with-resources 정리
  • [JAVA] 자바 부모클래스 및 인터페이스 심화: 오버라이딩과 메서드 동작
  • [JAVA] 추상 클래스 (Abstract Class) 정리
  • [JAVA] 접근 지정자 (Access Modifiers) 정리
개발자 동긔
개발자 동긔
배우고 느낀점들을 기록합니다. 열정 넘치는 백엔드 개발자로 남고싶습니다.
  • 개발자 동긔
    Donker Dev
    개발자 동긔
  • 전체
    오늘
    어제
    • Category (39)
      • BackEnd (23)
        • JAVA (15)
        • Spring & JPA (7)
      • Database (4)
      • Computer Science (2)
        • Network (0)
        • Security (0)
        • Web (1)
      • DevOps (6)
        • Docker (1)
        • Jenkins (0)
        • Monitoring (2)
        • CICD (1)
      • 트러블 슈팅 (3)
      • 성능 개선 (1)
      • Project (0)
  • 인기 글

  • 태그

    인터페이스
    Spring
    nginx
    docker
    CICD
    spring cloud msa
    Jenkins
    java
    mysql master/slave replication
    docker compose
    restful api 설계
    SSH
    master/slave db 이중화 처리
    spring boot
    Database
    restful api
    interface
    JPA
    와일드카드
    @RequestBody
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
개발자 동긔
[JAVA] 인터페이스 정리
상단으로

티스토리툴바