프로그래밍/Java

[Java] 추상클래스(Abstract Class)와 인터페이스(Interface)에 대한 고찰

Jay Tech 2018. 11. 28. 14:36
반응형

추상 클래스(Abstract Class)란 미완성 설계도라고 할 수 있다. 자동차에 비유하면 완성되지 않은 자동차라고 할 수 있다. 차체만 있고 아직 바퀴를 달지 않은 그 상태를 미완성이라고 할 수 있다. 바퀴가 없으면 달릴수가 없으니 이것은 자동차라고 아직은 말 할 수가 없다. 


마찬가지로 추상 클래스는 객체를 생성할 수 없다. (즉, 바퀴를 달게 하지 않은 설계도로는 자동차를 만들 수 없다.) 


추상클래스의 선언은 class 앞에 abstract를 붙이면 된다. 그리고 추상 클래스는 추상메서드를 포함하고 있고 여느 클래스와 마찬가지로 생성자와 멤버변수도 가질 수 있다. 


여기서 인터페이스(interface)와 비교를 해보자. 인터페이스는 추상 클래스에서 더 추상화 된 것이다. 그래서 모든 메서드는 public abstract으로 선언되고, 모든 멤버 변수는 public static final로 선언되어야 한다. 즉 멤버 변수는 아니고 상수라고 하는게 맞겠다. 저 키워드들은 생략이 가능하며 컴파일 단계에서 자동으로 추가해준다. JDK 1.8부터는 인터페이스에 static 메서드와 디폴트 메서드를 선언하는 것을 허용한다. 이런 이유는 인터페이스를 구현 받는 클래스마다 기능추가를 하기 어려울 상황에 대비를 하기 위함이다. 


사실 저렇게 되어버리면 인터페이스라는 것과 추상 클래스라는 것의 경계가 없어지는 듯 하다. 하지만 둘이 목적성이 다르다. 


기본적으로 추상클래스는 상속을 통해 기능을 확장하려는 목적을 가지고 있다. 

이에 반해 인터페이스는 인터페이스를 구현한 객체들에 대해 동일한 동작을 약속하는 것이다. 


사실 이러한 내용들은 많이 널려있다. 오늘 써볼 얘기는 추상 클래스에 대한 깊은? 내용이다. 안드로이드를 하다가 아주 기본적인 코드작성에 있어서 의문점이 생겼었다. 


1
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
cs


이 코드는 시스템에 접근하여 단말기를 진동시키기 위한 코드이다. (몰라도 된다 사실 내용이 중요한게 아니다) 

내부가 어떻게 구현되어있는지 보기 위해서 Vibrator 클래스를 열어 보았다. 그런데 왠걸 abstract이 아닌가?





저 위에 코드는 abstract class로 객체생성을 한 것이다. 분명 abstract는 객체생성을 할 수 없는데 지금 저것만 봐서는 객체 생성을 한것으로 보인다. 구글링을 해보니 stackoverflow에 "추상클래스가 Anonymous SubClass 를 생성한다." 라고 누군가가 답변한것을 보았다.






???


익명 서브 클래스를 생성을 한다?? 익명 클래스면 익명클래스고 서브 클래스면 서브 클래스지 익명 서브클래스는 무엇인가.

멘토님한테 여쭤보았다. 그랬더니 바로 코드를 짜주시면서 설명해주셨다.... ㄷㄷ


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
abstract class Vibrator {
    public abstract void shake();
}
 
class VibratorImpl extends Vibrator {
    @Override
    public void shake() {
        System.out.println("VibratorImpl called");
    }
}
public class Main {
    public static void main(String[] args) {
        Vibrator v1 = getVibrator1(); // 명시적 클래스
        Vibrator v2 = getVibrator2(); // 익명 클래스
 
        v1.shake();
        v2.shake();
    }
 
    static Vibrator getVibrator1() {
        return new VibratorImpl();
    }
    
    static Vibrator getVibrator2() {
        // 익명 클래스 
        return new Vibrator() {
            @Override
            public void shake() {
                System.out.println("getVibrator2 called");
            }
        };
    }
}
cs


예를들어, 이런식으로 내부적으로 추상클래스를 구현한 객체가 있고 반환 타입을 추상클래스 타입으로 주는 것이다. 그래서 추상클래스가 객체를 만든 것 처럼 보이는 것이다. 저렇게 추상클래스를 구현한 객체를 만들 수도 있고 익명클래스로 구현한 객체를 만들 수 있는 것이다. getVibrator2가 익명 서브 클래스를 구현한 것이다. 익명으로 자식 클래스를 구현 했다는 말이다.


결과적으로 내가 호출한 Vibrator 추상클래스도 getSystemService에서 내부적으로 온전한 클래스가 객체를 생성하여 반환하는 것이다. 

반응형