인터페이스란 무엇일까?

작은선생·2023년 11월 24일
post-thumbnail

추상클래스와 인터페이스는 깊은 연관성이 있다. 인터페이스도 일종의 추상클래스이기 때문이다.

인터페이스는 무엇인지, 또 추상클래스와 어떤 다른 어떤 특징을 가지는지 알아보자.

인터페이스란?

추상클래스의 일종이지만, 추상클래스보다 추상도 즉, ‘강제성’이 더 강하다고 보면된다.

추상클래스와 다르게 인터페이스는 일반메소드, 멤버변수를 가질 수 없다.

오로지 추상메소드 혹은 상수만 가질 수 있다. 그외에 어떤 요소도 허용되지 않는다.

인터페이스를 작성하는건 어렵지 않다.

interface Inter {
		//1
		public final int a = 1;
		public abstract void play();
		
		//2
		int b = 1;
		void plaing();
		
		//3
		default void plaingNumber() {
			
		}
}
  1. 인터페이스는 interface 란, 용어를 사용해 인터페이스를 선언할 수 있다.

    단, 접근제어자로 public default 만 사용할 수 있다.

  1. 모든 멤버변수는 public static final 이어야하며, 생략가능하다.

    메서드는 public abstract 이어야하며, 생략가능하다.

    (JDK 1.8 이상에서 staticdefault 메소드는 예외.) → 추상 메소드가 아니어도, 선언이 가능.

일반 클래스와 다른 인터페이스 상속

인터페이스는 인터페이스간 상속만 가능하다.

단, 일반클래스와 다르게 ‘다중상속’이 가능하다.

interface Inter extends Player, Listener{
      
}

interface Player {}

interface Listener {}

인터페이스 구현

단계적으로 인터페이스 구현에 대해 알아보자.

class InterTest implements Inter {}

인터페이스 또한 추상클래스처럼 인스턴스를 생성할 수 없는 것은 물론 추상클래스가 상속을 위해 extends 를 사용했다면, 인터페이스는 implements 라고 선언해줘야한다.

물론, 추상클래스와 동일하게 ‘미완성 메소드’ 들은 모두 명시해야하는 ‘강제성’을 띈다.

interface Inter extends CDPlayer, Listener{
		default void pass () {
	            
	  }
		static void pass2 () {
	            
	  }
}

interface CDPlayer {
    void musicIng();
}

interface Listener {
    void musicStart();
    void musicStop();
    void singing();
}

조금의 코드를 추가해보자. CDPlayer Listener 인터페이스에 추상메소드를 각각 작성해주었다.

Inter 라는 이름의 인터페이스는 CDPlayer Listener 인터페이스를 모두 상속받고, 중요한 점이 몇 가지 존재한다.

  • 다중상속이 가능하다는걸 확인할 수 있다.
  • 인터페이스 - 인터페이스 간 상속임에도 부모 인터페이스의 추상메소드들이 선언되지 않아도 된다는 것을 확인할 수 있다. 정확히는 명시하지 않아도 작동한다. (모두 추상 메소드이기에 따로 선언할 이유가 없음) → 일반 클래스 - 추상 클래스 간 상속에서 추상메소드는 반드시 명시가 ‘강제’되었던 것과는 다르다.
  • 인터페이스 - 인터페이스간 상속은 extends 를 사용한다.
  • 인터페이스 내 default static 메소드 생성이 가능하며, ‘강제성이 없는' 일반 메소드 활용이 가능하다. (단, JDK 1.8 이상에서 가능하며, 인터페이스를 활용할 경우에는 항상 메소드 간 충돌을 주의해야한다.)
class InterTest implements Inter {
    @Override
    public void musicIng() {

    }

    @Override
    public void musicStart() {

    }

    @Override
    public void musicStop() {

    }

    @Override
    public void singing() {

    }
}

이제 일반 클래스에 인터페이스를 구현할 InterTest 라는 ‘구현체’를 작성해보자.

  1. 당연히, 인터페이스의 추상메소드들은 모두 명시되어 구현되어야한다.
  2. implements 를 활용해 일반 클래스에 상속할 수 있다.

엄연히, implementsextends 는 다르다. 그리고 둘은 동시에 사용할 수 있다는 점도 알아야한다.

InterTest 구현체에 상속받을 임의의 클래스를 하나 생성해 InterTest 클래스와 상속해보자.

class InterTest extends InterTestExtension implements Inter {
    @Override
    public void musicIng() {

    }

    @Override
    public void musicStart() {

    }

    @Override
    public void musicStop() {

    }

    @Override
    public void singing() {

    }

    @Override
    void add() {
        super.add();
    }

    @Override
    void delete() {
        super.delete();
    }
}

class InterTestExtension {
    void add () {}

    void delete () {}
}

임의의 InterTestExtension 이라는 클래스를 생성해, InterTestextends 를 활용해 상속했다.

클래스에 **<span style="color:rgb(165, 102, 255)">extends 를 활용한 ‘상속’ 과 implements 를 활용한 ‘구현’은 동시에 가능하다는 점**을 기억해야한다. (당연히, 추상클래스로 선언해 상속도 가능할 것이다.)

인터페이스를 활용한 다형성

우리는 다형성을 활용해 자손클래스의 인스턴스를 조상타입의 참조변수로 참조할 수 있다.

인터페이스 타입의 참조변수를 구현한 클래스의 인스턴스를 참조할 수 있고, 인터페이스로의 형변환도 가능하다.

예를들어 다음과 같다.

void methodInter(Inter a) { //1

}

Inter methodInterTwo() { //2

    return new InterTest();
}
  1. 인터페이스를 참조변수로 사용할 수 있다.

  2. 메소드 리턴타입을 인터페이스로 지정할 수 있고, 그에 따라 ‘구현체’인 InterTest() 를 리턴할 수도 있다.

    ⇒ 구현체가 구현한 메소드 정보를 활용할 수 있단 뜻.

정리

  • 개발시간 단축

    → 인터페이스는 선언부만 작성 후, 이후 내용들은 각 구현체에서 구현되기 때문에 독립적이고, 다수의 작업을 동시에 진행할 수 있다.

  • 추상화를 통한 표준화

    → 추상클래스보다 강화된 ‘강제성’을 활용해 특정 공통기능을 구현하는 클래스들이 인터페이스를 활용함으로써 조금 더 획일화된 프로그래밍을 진행할 수 있다.

  • 클래스들간의 관계성 확립가능

    → 시스템이 복잡해지면 수 십개 혹은 수 백개의 클래스가 생성될 수 있는데, 인터페이스를 활용하면 어떤 클래스가 어떤 기능을 지녀야하고 지니고 있는지 파악하기 쉬워지고 그에 따른 관계도 파악하기 쉽다.

0개의 댓글