Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are constructors accessed?

Tags:

java

I've never understood why we're able to call constructors for a class from other classes. A constructor is a method, and normally when trying to call a method from a class, we'd have to either make that method static so we can access it as

MyClass.method();

or we'd make an instance of that class and then call that method (now obviously this method would contradict the premise of this question)

MyClass myClass = new MyClass();
myClass.method();

But in the case of a constructor we do neither. How does Java call the constructor of a class without doing either of these methods? I know that a constructor for a class must be visible to the class you're invoking it from, i.e if the class constructor you're invoking is in a different package, you have to import that package.

So how does Java handle invoking constructors with respect to being able to invoke them without using the methods above?

like image 865
d881m Avatar asked Jun 20 '21 00:06

d881m


1 Answers

Class constructors have special support in the Java language and Java bytecode beyond that given to normal methods. In particular, they get the special name <init> and are invoked using a different bytecode instruction (invokespecial as opposed to invokevirtual which is used for your typical method-call-with-runtime-dispatch that normal method calls look like).

Quoting from JVMS (JVM spec) section 3.8:

Java Virtual Machine class instances are created using the Java Virtual Machine's new instruction. Recall that at the level of the Java Virtual Machine, a constructor appears as a method with the compiler-supplied name <init>. This specially named method is known as the instance initialization method (§2.9). Multiple instance initialization methods, corresponding to multiple constructors, may exist for a given class. Once the class instance has been created and its instance variables, including those of the class and all of its superclasses, have been initialized to their default values, an instance initialization method of the new class instance is invoked. For example:

Object create() {
   return new Object();
}

compiles to:

Method java.lang.Object create()
0   new #1              // Class java.lang.Object
3   dup
4   invokespecial #4    // Method java.lang.Object.<init>()V
7   areturn

As you can see, the reference compiler that was used to generate this sample first creates an uninitialized instance of the object in question, pushes it on the stack along with any constructor parameters (not shown), and uses invokespecial to invoke the appropriate constructor to initialize the object. At the language level, Java will not let you write code that exposes the completely uninitialized object before the constructor is invoked, although you can still leak a partially constructed object.

It's worth noting that there are unsafe means (literally in a hidden-away class called Unsafe) to obtain a reference to an object that is initialized at a low level but whose constructor is never called. These somewhat break out of the Java language spec, and should only be used with extreme care where absolutely needed.

like image 96
nanofarad Avatar answered Oct 03 '22 12:10

nanofarad