La foret rouge
Published on

바이트코드로 보는 Java 클래스 기본 생성자와 메소드 반환문

Authors
  • avatar
    Name
    신주용

기본 생성자 (default constructor)

모든 자바 클래스에는 적어도 하나 이상의 생성자가 정의되어야 합니다.

// 생성자 없음
class A {

}

// 기본 생성자
class B {
    public B () {}
}

생성자의 특징

생성자는 다음과 같은 특징이 있습니다12.

  1. 생성자의 이름은 클래스 이름과 동일해야 하고, 반환 타입을 가지면 안됩니다(void도).
  2. 하나의 클래스 안에 같은 수와 타입의 인자를 갖는 생성자를 여러 개 추가할 수 없습니다.
  3. 생성자는 객체가 생성될 때 호출됩니다.
  4. 생성자를 명시적으로 정의하지 않았다면, 자바 컴파일러가 자동으로 기본 생성자를 추가해 줍니다.

기본 생성자 자동 추가

이번 포스팅에서는 4번 단계를 깊게 살펴봅니다. 우선, 임의의 클래스 Gumi를 작성했습니다. Gumi 클래스는 생성자가 정의되지 않은 상태입니다. 추가로, return이 없는 void 메소드 a()도 있습니다.

public class I {
    public static void main(String[] args) {
        Gumi gumi = new Gumi();
    }
}

class Gumi {
    void a() {

    }
}

자바는 우리가 작성한 코드를 바이트코드라는 중간 언어로 먼저 컴파일한 후, 이를 JVM에서 실행합니다. 생성자를 정의하지 않은 클래스를 컴파일하면 자바 바이트코드에는 어떻게 표현되는지를 알아보기 위해 javap 명령어를 사용해봅시다3.

$ javac I.java

$ ls
Gumi.class  I.java  I.class

$ javap -v Gumi.class
Classfile /.../Gumi.class
  Last modified Jul 22, 2023; size 222 bytes
  MD5 checksum eb6c509a700b5264c73e4275c16a4722
  Compiled from "I.java"
class Gumi
  minor version: 0
  major version: 52
  flags: ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#11         // java/lang/Object."<init>":()V
   #2 = Class              #12            // Gumi
   #3 = Class              #13            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               a
   #9 = Utf8               SourceFile
  #10 = Utf8               I.java
  #11 = NameAndType        #4:#5          // "<init>":()V
  #12 = Utf8               Gumi
  #13 = Utf8               java/lang/Object
{
  Gumi();
    descriptor: ()V
    flags:
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0

  void a();
    descriptor: ()V
    flags:
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 9: 0
}
SourceFile: "I.java"
  • major version: 52: 자바 1.8 버전을 사용했습니다.

  • Gumi(); descriptor: ()V: 자동으로 추가된 기본 생성자입니다. 파라미터가 없고, 반환 타입은 Void입니다4.

  • Gumi(); Code: ... 1: invokespecial #1 // Method java/lang/Object."<init>":()V: 자바의 모든 클래스는 Object 클래스를 상속합니다. 이 부분을 자바 코드로 표현하자면 다음 코드와 같습니다.

    class Gumi extends Object {
      public Gumi () {
        super();
      }
    }
    
  • void a(): descriptor: ()V: a() 메소드도 우리가 처음 자바코드에 작성한 것처럼 반환값이 void 타입인 메소드입니다.

  • void a(): Code: 0: return: 여기에서도 자바 소스코드에서는 return문을 안 적었으나 자바가 자동으로 추가해준 것을 확인할 수 있습니다.

결과

이 결과를 통해

  1. 클래스에 생성자가 명시적으로 정의되어 있지 않다면 자바가 자동으로 기본 생성자를 추가해 주는 것을 확인했고,
  2. 반환값이 void 타입인 메소드여서 return을 안 적었더라도 이 또한 자동으로 추가해 주는 것을 확인할 수 있었습니다.

Footnotes

  1. W3Schools "Java Constructors." www.w3schools.com. https://www.w3schools.com/java/java_constructors.asp (accessed Jul. 22, 2023).

  2. Oracle. "Providing Constructors for Your Classes." docs.oracle.com. https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html (accessed Jul. 22, 2023).

  3. Anshul Bansal. "View Bytecode of a Class File in Java." www.baeldung.com. https://www.baeldung.com/java-class-view-bytecode (accessed Jul. 22, 2023).

  4. Oracle. "Field Descriptors." docs.oracle.com. https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3 (accessed Jul. 22, 2023).