본문 바로가기

Java 문법 개념

추상클래스 vs 인터페이스

추상클래스

추상메서드(미완성 메서드)를 1개 이상 가지고 있는 "클래스"

 

1. 추상클래스의 구성요소.

추상 클래스는 추상메서드를 가지고 있을 뿐이고 특성이나 내부 요소는 일반적인 클래스와 완전히 동일하다고 이해해야한다.

따라서, 일반적인 클래스가 가질 수 있는 멤버(iv, cv), 생성자, 인스턴스 메서드, 스태틱 메서드를 추상클래스 또한 마찬가지로 가질 수 있다.(추상 클래스의 구성요소가 인터페이스와의 차이점 중 핵심적인 부분이다.)

클래스의 구성요소에 단순하게 추상메서드만 추가된 것으로 이해하면 어렵지 않다.

 

2. 추상클래스는 객체를 만들 수 없다.

추상클래스는 추상메서드(미완성 메서드)를 가지고 있기에 추상 클래스를 바탕으로 객체를 생성할 수 없다. 설계도가 미완성인 셈이니 미완성된 설계도로 객체라는  제품을 만들 수 없는 것은 당연할 것이다.

 

3. 추상클래스의 상속과 구현 _ extends

추상클래스는 구현상속 이라는 단어의 사용을 공통(공용)으로 사용한다. 왜냐하면 자손 클래스가 추상클래스를 상속받으면서 추상클래스에 작성된 추상메서드를 자손 클래스에서 구현시키기 때문이다.

즉 상속이 곧 구현인 셈이다.(인터페이스는 다름!) 이때 사용하는 키워드는 extends 이다.

 

추상클래스는 여러 클래스에서 공통으로 사용될 수 있는 부분을 추출하여 추상클래스에 작성해두는 방식으로 사용한다. 나중에 추상클래스에 작성된 코드가 필요할 경우 이를 상속받고 자손 클래스에서 구현해서 사용하면 되니, 코드의 중복이 줄어드는 효과가 생긴다.

 

추상클래스를 상속받을 때 반드시 조상클래스에 존재하는 모든 추상메서드들을 한번에 구현해야할 필요는 없지만, 이럴 경우 아직 구현이 완료되지 않은 추상메서드가 여전히 존재하는 것이기 때문에 상속을 받은 자손 클래스 또한 추상클래스가 된다.

 


인터페이스

"추상메서드의 집합".

(정의내리는 방식은 사람마다 다양하겠지만 우선 이렇게 정의하고 싶다..)

 

1. 인터페이스의 구성요소

인터페이스는 내부 구성 요소로 추상메서드, 상수, static 메서드, default 메서드 을 가진다. 

JDK1.8 부터 인터페이스의 구성요소로서 static 메서드와 default 메서드가 추가되었지만, 인터페이스의 핵심적인 구성요소는 바로 추상메서드이다. 

 

그리고 인터페이스는 인스턴스 변수와 생성자를 가질 수 없다.(추상클래스와 차이점)

 * 참고로 static 메서드와 default 메서드는 구현부가 있는 구상메서드 이다.(추상메서드의 반댓말)

 * 왜 인터페이스에 구상메서드를 넣을 수 있게 된 것인지는 나중에 적겠다.( 2 -1 참고 )

 

2. 인터페이스 구성요소의 제어자

인터페이스의 상수는 반드시 public static final 이며, 이는 반드시 존재해야하는 제어자로 처리기 때문에 생략이 가능하며 생략된 경우에는 컴파일러가 자동으로 넣어준다. ^^

 

인터페이스의 추상메서드는 반드시 public abstract 이며, 이 또한 마찬가지로 반드시 존재하는 제어자로 처리되기 때문에 생략이 가능하며, 생략된 경우 컴파일러가 자동으로 넣어준다.

 + 참고로, Java 에서 이미 설계되어 작성되어진 인터페이스의 내부 코드를 확인해보면, 내부에 정의되어 있는 메서드는 분명히 구현부가 없는 abstract 메서드가 분명한데 제어자에는 abstract가 작성되어 있지 않다.

 + 대표적으로 Comparator 인터페이스의 내부 코드를 보면 public abstract int compare(T o1, T o2); 가 아닌, int compare(T o1, T o2); 로만 작성되어 있는 것도 같은 이유이다.

 

인터페이스의 static 메서드와 default 메서드는 구상메서드이다. 과거에는 인터페이스 내부에는 오직 추상메서드만 작성할 수 있는 것으로 설계되었지만 추후에 추가되었다고 한다...( 아래 2-1 참고 )

참고로, default 메서드의 default 는 접근제어자의 default 가 아니고 이 둘은 아무런 관련도 없으니 혼동하지 말자. 접근제어자의 default 는 적지 않지만, 인터페이스의 default 메서드는 default를 적는다.

 

2 -1. 인터페이스에 구상메서드가 존재하는 이유. (참고) 

'추상메서드의 집합' 이라고 불릴 정도로 추상메서드가 메인이던 인터페이스에, 구상메서드가 추가된 이유는 일종의 '개발의 편의'를 위해서이다.

 

이미 만들어진 인터페이스를 구현하고 있는 클래스가 여럿 존재하는 상태에서, 그 인터페이스에 새롭게 추상메서드를 추가해야한다면, 해당 인터페이스를 구현하고 있는 모든 클래스에서 새롭게 추가된 추상클래스를 전부 구현시켜줘야하는 아주 번거로운 일이 발생한다....(하나의 인터페이스 당 연결[=구현]된 클래스의 갯수가 많을 수록 번거로움은 비례하여 증가한다...)

 

따라서 이 문제에 대한 해결책으로, 구상메서드인 디폴트 메서드가 인터페이스의 기능에 추가됬다.

이미 구현이 되어진 구상메서드를 인터페이스에 넣어준다면, 당연하게도 해당 메서드는 구현될 필요가 없어지기 때문에(오버라이딩 할게 아니라면..) 앞서 말한 번거로움이 해결될 것이다.

 

디폴트 메서드는 구상메서드이며 인스턴트 메서드이다. 그리고 앞서 말한 것처럼 반드시 앞에 default 를 붙여야한다. 또한 마찬가지로 앞서 언급한 인터페이스의 규칙 중, '모든 추상메서드는 public abstract 이어야 한다' 라 는 규칙으로 인해 디폴트 메서드의 접근제어자 또한 public 으로 고정되며 생략이 가능하다.

 

하지만, 인터페이스에 구상메서드의 작성을 허용할 경우 충돌가능성이 생긴다. 해당 인터페이스가 상속계층도 상에서 높은 계층일 수록 그 충돌가능성은 더 높아질 것이다.

 

( * 여기서 충돌이란, 각 클래스에서 메서드 이름은 동일하면서 구현부는 다른 메서드가 각각 존재할 때, 만약에 클래스의 다중상속을 허용하고,(말그대로 가정이고 Java는 실제로는 다중상속 불가능) 하나의 클래스에 다중상속을 시키면 이때 충돌이 발생한다. 메서드 이름은 동일한데 구현부는 다른 메서드들을 상속받으니 어떤 메서드를 상속받아야 할지 판단할 수 없는 것이다. )

 

디폴트 메서드의 이런 충돌문제는 경우의 수와 각 해결법이 2가지로 나뉘는데, 다음과 같다.

  1.  여러 인터페이스의 디폴트 메서드 간 충돌  -> 구현한 클래스에서 디폴트 메서드를 오버라이딩
  2. 조상클래스와 인터페이스의 디폴트 메서드와 충돌 -> 조상클래스의 메서드가 우선적으로 상속되고 디폴트메서드 무시됨.

 

3. 인터페이스는 객체를 만들 수 없다.

추상클래스 부분에서 작성한 내용과 같은 이유 때문이다. 생략!!

 

4. 인터페이스의 상속과 구현 _ extends & implements

 

 

 

---- 작성중...