사람들은 흔히들 추상클래스는 객체 생성이 불가능하다고 알고 있습니다.
하지만 정말 그럴까요?
public abstract class AAA {
{
System.out.println("aaaa");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
우선 부모 클래스 AAA 라고 만들었습니다(네이밍룰은 레드썬!)
자세히 보면 기본블럭(default block) 을 이용해서 객체가 생성되면 자동적으로 aaaa 라는 문자열을 찍도록 해 두었습니다.
자식 클래스는 당연히 AAA클래스를 상속해서 만들었습니다.
public class BBB extends AAA {
{
System.out.println("BBB");
}
public static void main(String[] args) {
BBB obj1 = new BBB();
System.out.println(obj1);
BBB obj2 = new BBB();
System.out.println(obj2);
}
}
별다른 내용은 없고 메인 메소드를 작성해서 객체를 두개 만들어 보았습니다. 다만 객체 생성을 확인하기 위해서 BBB클래스 역시 기본 블럭으로 BBB라는 문자열을 출력하도록 수정했습니다. 이 코드의 컴파일 결과 부터 살펴봅니다.
[parsing started BBB.java]
[parsing completed 32ms]
[search path for source files: .]
역시 BBB.java 파일을 메모리로 파싱합니다.
그런데 BBB클래스는 AAA를 상속하기 때문에 AAA역시 필요하게 됩니다.
[loading .\AAA.java]
[parsing started .\AAA.java]
[parsing completed 0ms]
[loading java\lang\Object.class(java\lang:Object.class)]
[loading java\lang\String.class(java\lang:String.class)]
[checking BBB]
[loading java\lang\System.class(java\lang:System.class)]
[loading java\io\PrintStream.class(java\io:PrintStream.class)]
[loading java\io\FilterOutputStream.class(java\io:FilterOutputStream.class)]
[loading java\io\OutputStream.class(java\io:OutputStream.class)]
[checking AAA]
[wrote .\AAA.class]
[checking BBB]
[wrote BBB.class]
[total 281ms]
이 코드를 가지고 실행하게 될 코드는 어떻게 될까요?
javap 명령을 이용해서 역컴파일 시킨 결과는 다음과 같습니다.
Compiled from "BBB.java"
public class BBB extends AAA
SourceFile: "BBB.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #8.#17; // AAA."<init>":()V
const #2 = Field #18.#19; // java/lang/System.out:Ljava/io/PrintStream;
const #3 = String #20; // BBB
const #4 = Method #21.#22; // java/io/PrintStream.println:(Ljava/l
ang/String;)V
const #5 = class #20; // BBB
const #6 = Method #5.#17; // BBB."<init>":()V
const #7 = Method #21.#23; // java/io/PrintStream.println:(Ljava/l
ang/Object;)V
const #8 = class #24; // AAA
const #9 = Asciz <init>;
const #10 = Asciz ()V;
const #11 = Asciz Code;
const #12 = Asciz LineNumberTable;
const #13 = Asciz main;
const #14 = Asciz ([Ljava/lang/String;)V;
const #15 = Asciz SourceFile;const #16 = Asciz BBB.java;
const #17 = NameAndType #9:#10;// "<init>":()V
const #18 = class #25; // java/lang/System
const #19 = NameAndType #26:#27;// out:Ljava/io/PrintStream;
const #20 = Asciz BBB;
const #21 = class #28; // java/io/PrintStream
const #22 = NameAndType #29:#30;// println:(Ljava/lang/String;)V
const #23 = NameAndType #29:#31;// println:(Ljava/lang/Object;)V
const #24 = Asciz AAA;
const #25 = Asciz java/lang/System;
const #26 = Asciz out;
const #27 = Asciz Ljava/io/PrintStream;;
const #28 = Asciz java/io/PrintStream;
const #29 = Asciz println;
const #30 = Asciz (Ljava/lang/String;)V;
const #31 = Asciz (Ljava/lang/Object;)V;
{
public BBB();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method AAA."<init>":()V 4: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3; //String BBB
9: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
12: return
LineNumberTable:
line 2: 0
line 5: 4
line 6: 12
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=3, Args_size=1
0: new #5; //class BBB
3: dup
4: invokespecial #6; //Method "<init>":()V
7: astore_1
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Obj
ect;)V
15: new #5; //class BBB
18: dup
19: invokespecial #6; //Method "<init>":()V
22: astore_2
23: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Obj
ect;)V
30: return
LineNumberTable:
line 12: 0
line 13: 8
line 15: 15
line 16: 23
line 18: 30
}
코드를 보면 내부적으로 AAA클래스 역시 로딩하는 것을 확인할 수 있습니다.
실행된 결과는 더욱 재밌습니다.
aaaa
BBB
BBB@c17164
aaaa
BBB
BBB@1fb8ee3
객체를 두 개 만들었더니 AAA안의 기본 블럭 역시 두번(즉 AAA클래스의 객체도 두번 만들어진다) 실행되는 것을 볼 수 있습니다.
Java에서 추상 클래스는 문법적으는 객체 생성을 제약하는 것이 맞습니다. 즉 직접 객체를 생성할 수 없도록 하는 장치라는 겁니다.
하지만 상속이라는 것이 실제로 객체를 한번에 부모 클래스까지 만들어 내기 때문에 추상클래스 역시 그 예외가 아니라는 겁니다.
유익한 글 감사합니다 !
답글삭제작성자가 댓글을 삭제했습니다.
답글삭제