Ok, so i'm study for my first java certification and i can't quite understand exactly what happens underneath the hood when an object is created, some explanations that iv'e read states that the constructor returns the reference to an object which is a source of confusion for me because from my understanding this is done by the new keyword. My questions are:
Where does the reference to an object actually come from, the 'new' keyword or the constructor?
When an object is created using the 'new' keyword, does it implicitly pass this object to the constructor?
When an object is created using the 'new' keyword, is it just a java Object until it is passed to the constructor eg. Person me = new Person(); Is this object associated with the class person as soon as it is created, or only after it has been passed to the constructor
The entire expression of new Constructor(arguments) is considered one instance-creation expression, and is not meaningful as a separate new keyword and constructor call.
The JLS, 15.9.4 describes the actual creation of the instance, which is comprised of three steps:
Qualifying the expression (not applicable when using new)
Allocating space for the instance in memory, and setting fields to default values.
Evaluating arguments for the constructor, and calling the constructor.
First, if the class instance creation expression is a qualified class
instance creation expression, the qualifying primary expression is
evaluated. If the qualifying expression evaluates to null, a
NullPointerException is raised, and the class instance creation
expression completes abruptly. If the qualifying expression completes
abruptly, the class instance creation expression completes abruptly
for the same reason.
Next, space is allocated for the new class instance. If there is
insufficient space to allocate the object, evaluation of the class
instance creation expression completes abruptly by throwing an
OutOfMemoryError.
The new object contains new instances of all the fields declared in
the specified class type and all its superclasses. As each new field
instance is created, it is initialized to its default value (§4.12.5).
Next, the actual arguments to the constructor are evaluated,
left-to-right. If any of the argument evaluations completes abruptly,
any argument expressions to its right are not evaluated, and the class
instance creation expression completes abruptly for the same reason.
Next, the selected constructor of the specified class type is invoked.
This results in invoking at least one constructor for each superclass
of the class type. This process can be directed by explicit
constructor invocation statements (§8.8) and is specified in detail in
§12.5.
The value of a class instance creation expression is a reference to
the newly created object of the specified class. Every time the
expression is evaluated, a fresh object is created.
Yes, as bytecode this all turns into one invokespecial call with the new instance at the bottom of the stack of parameters passed. Please see the bottom of this answer. Semantically, however, the constructor doesn't get the new instance "passed" to it, but that instance is made available as this in Java source code.
This question doesn't make semantic sense, as the object doesn't "exist" to the outside world until the constructor returns. If the construction terminates abruptly, the object is not actually created and available. However, in memory on an OpenJDK JVM at least, the type of the object as well as any types that it extends/implements are written to an in-memory header. This is not guaranteed for all implementations, however.
Disassembly:
I compiled and disassembled:
class Test{
public static void main(String args[]){
Integer s = new Integer(2);
}
}
This is the result:
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
8: astore_1
9: return
As you can see, first the object is allocated using new, which fills in all fields as defaults. It's duplicated, so the stack looks like:
our new Integer
our new Integer
The constant value that I passed to the constructor is then pushed:
2
our new Integer
our new Integer
invokespecial occurs, which passes the top two stack elements--the new instance, and the constructor's parameter.
Related
The ASM guide talks about constructors:
package pkg;
public class Bean {
private int f;
public int getF() {
return this.f;
}
public void setF(int f) {
this.f = f;
}
}
The Bean class also has a default public constructor which is
generated by the compiler, since no explicit constructor was defined
by the programmer. This default public constructor is generated as
Bean() { super(); }. The bytecode of this constructor is the
following:
ALOAD 0
INVOKESPECIAL java/lang/Object <init> ()V
RETURN
The first instruction pushes this on the operand stack. The second
instruction pops this value from the stack, and calls the <init>
method defined in the Object class. This corresponds to the super()
call, i.e. a call to the constructor of the super class, Object. You
can see here that constructors are named differently in compiled and
source classes: in compiled classes they are always named <init>,
while in source classes they have the name of the class in which they
are defined. Finally the last instruction returns to the caller.
How is the value of this already known to the JVM before the first instruction of the constructor?
At the JVM level, first the object is allocated, uninitialized, then the constructor is invoked on that object. The constructor is more-or-less an instance method executed on the uninitialized object.
Even in the Java language, this exists and has all its fields at the first line of the constructor.
The first thing to understand, is how object instantiation work on the bytecode level.
As explained in JVMS, §3.8. Working with Class Instances:
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
So the constructor invocation via invokespecial shares the behavior of passing this as the first argument with invokevirtual.
However, it must be emphasized that a reference to an uninitialized reference is treated specially, as you are not allowed to use it before the constructor (or the super constructor when you’re inside the constructor) has been invoked. This is enforced by the verifier.
JVMS, §4.10.2.4. Instance Initialization Methods and Newly Created Objects:
… The instance initialization method (§2.9) for class myClass sees the new uninitialized object as its this argument in local variable 0. Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass.
When doing dataflow analysis on instance methods, the verifier initializes local variable 0 to contain an object of the current class, or, for instance initialization methods, local variable 0 contains a special type indicating an uninitialized object. After an appropriate instance initialization method is invoked (from the current class or its direct superclass) on this object, all occurrences of this special type on the verifier's model of the operand stack and in the local variable array are replaced by the current class type. The verifier rejects code that uses the new object before it has been initialized or that initializes the object more than once. In addition, it ensures that every normal return of the method has invoked an instance initialization method either in the class of this method or in the direct superclass.
Similarly, a special type is created and pushed on the verifier's model of the operand stack as the result of the Java Virtual Machine instruction new. The special type indicates the instruction by which the class instance was created and the type of the uninitialized class instance created. When an instance initialization method declared in the class of the uninitialized class instance is invoked on that class instance, all occurrences of the special type are replaced by the intended type of the class instance. This change in type may propagate to subsequent instructions as the dataflow analysis proceeds.
So code creating an object via the new instruction can’t use it in any way before the constructor has been called, whereas a constructor’s code can only assign fields before another (this(…) or super(…)) constructor has been called (an opportunity used by inner classes to initialize their outer instance reference as a first action), but still can’t do anything else with their uninitialized this.
It’s also not allowed for a constructor to return when this is still in the uninitialized state. Hence, the automatically generated constructor bears the required minimum, invoking the super constructor and returning (there is no implicit return on the byte code level).
It’s generally recommended to read The Java® Virtual Machine Specification (resp. its Java 11 version) alongside to any ASM specific documentation or tutorials.
So i was playing around in java once again and while doing so, i ran into an interesting problem.
I was trying to write my self a little registration service. If an object of a certain type is instantiated via its constructor it would retrieve an id from my registration service and is added to the services list of objects.
Here is an example object
public class Test {
private final Long id;
public Test() {
this.id = TestRegistration.register(this);
throw new IllegalAccessError();
}
public Long getId() {
return this.id;
}
}
And here is an example service
public class TestRegistration {
private final static Map<Long, Test> registration = new HashMap<>();
protected final static long register(final Test pTest) {
if (pTest.getId() != null) {
throw new IllegalStateException();
}
long freeId = 0;
while (registration.containsKey(freeId)) {
freeId = freeId + 1;
}
registration.put(freeId, pTest);
return freeId;
}
protected final static Test get(final long pId) {
return registration.get(pId);
}
}
Now as you can see, the constructor of my class Test can't successfully execute at all since it always throws an IllegalAccessError. But the method register(...) of my TestRegistration class is called in the constructor before this error is thrown. And inside this method it is added to the registrations Map. So if i would run for example this code
public static void main(final String[] args) {
try {
final Test t = new Test();
} catch (final IllegalAccessError e) {
}
final Test t2 = TestRegistration.get(0);
System.out.println(t2);
}
My TestRegistration does in fact contain the object created when the constructor of my Test class was called and i can (here using variable t2) access it, even tho it wasn't successfully created in the first place.
My question is, can i somehow detect from within my TestRegistration class if the constructor of Test was executed successfully without any exceptions or other interruptions?
And before you ask why i throw this exception in the first place here is my answer. Test may have potential subclasses i don't know of yet but still will be registered in my TestRegistration class. But since i don't have influence on the structure of those subclasses i can't tell if their constructor will throw an exception or not.
It does not appear to be possible.
I've included the best I can gather from the JLS below.
As can be seen from that, the execution of the body of the constructor is the very last step in the creation of an object.
Thus I don't see any evidence to suggest that raising an exception would result in anything not happening which you could've checked to see whether the execution was successful (apart from the rest of the body of the constructor, obviously).
This may not seem particularly convincing, although I'm not convinced that you'd find anything more concrete than this (it is, after all, notoriously difficult to prove that something doesn't exist).
I would recommend putting the logic that modifies external data somewhere else.
It wouldn't be entirely unreasonable to require that a register method (either in the TestRegistration class, or in the object itself) be explicitly called after construction of an object.
It could also work to, instead of calling the constructors directly, have a class containing methods to return objects (which sounds a lot like the Factory Design Pattern), where you can then put this external modification logic.
From the JLS:
15.9.4. Run-Time Evaluation of Class Instance Creation Expressions
At run time, evaluation of a class instance creation expression is as follows.
First, if the class instance creation expression is a qualified class instance creation expression, the qualifying primary expression is evaluated. If the qualifying expression evaluates to null, a NullPointerException is raised, and the class instance creation expression completes abruptly. If the qualifying expression completes abruptly, the class instance creation expression completes abruptly for the same reason.
Next, space is allocated for the new class instance. If there is insufficient space to allocate the object, evaluation of the class instance creation expression completes abruptly by throwing an OutOfMemoryError.
The new object contains new instances of all the fields declared in the specified class type and all its superclasses. As each new field instance is created, it is initialized to its default value (§4.12.5).
Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.
Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type. This process can be directed by explicit constructor invocation statements (§8.8) and is specified in detail in §12.5.
The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created.
12.5. Creation of New Class Instances
...
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
Weather or not the constructor comples does not influence whether or not the object is created. All instance variables will be created the super() will still be called and memory will still be allocated.
In reality the exception will always be thrown, every object in your registration service will have thrown an exception. As children will have to call super() in order to be registered and following registration an exception is thrown.
According to the definitions of constructors they don't have any return types,but while creating object we often do A a = new A(); which is responsible for creating the object a.
A a=new A();
Can anyone help me understanding the issue,what is actually happening in the case of constructors while creation of Object.
Constructors don't have return types, correct. But the expression new A() does have a result: A reference to the newly-created object.
Here's what happens with new A():
An object is created
It's given the type A
The relevant A constructor is called with this referring to that new object
Once initialization is done, the expression completes
The result of the expression is the reference to the new object
This process is described in this tutorial on the Oracle Java site.
In many ways, it would be more accurate to call constructors initializers: The construction happens because of the new operator, not the constructor.
The fact that constructors don't actually do the construction is made particularly clear when an object is processed by multiple constructors, as is very common. Consider:
List<String> m = new LinkedList<String>();
One object is created (ignoring any fields the list may need to initialize), but five different constructors get called to initialize that one object, because LinkedList<E> subclasses java.util.AbstractSequentialList<E> which subclasses java.util.AbstractList<E> which subclasses java.util.AbstractCollection<E> which subclasses java.lang.Object, and each of those classes has to get its chance to initialize its part of the object that was created. So in order:
JVM creates the object
Object() is called to initialize Object stuff
AbstractCollection() is called to initialize its stuff
Then AbstractList()
Then AbstractSequentialList()
Then LinkedList()
And then finally the resulting (one) object's reference becomes the result of the new expression
One object, but five constructors required to initialize it. :-)
Constructors need not to return anything. They just constructs the current instance. That's all their job, part of object creation.
Creating objects:
A a = new A();
Declaration: The code set in bold are all variable declarations that associate a variable name with an object type.
Instantiation: The new keyword is a Java operator that creates the object.
Initialization: The new operator is followed by a call to a constructor, which initializes the new object.
Constructor declarations look like method declarations—except
that they use the name of the class and have no return type - from
the java constructor docs
To understand the constructor, it is similarly important to understand how it differs from a method.
Constructors have one purpose in life: to initialize the new object and it's fields. Nothing more. The new keyword handles the creation of memory space.
You shouldn't consider new A() to be a call to the constructor, because there are more things that happen, than just the constructor running. The major steps, when you run new A() are these.
A chunk of memory is set aside - just enough for storing an object of class A.
The constructor is run.
A reference to the chunk of memory that was set aside is returned.
So the constructor itself isn't actually returning anything - and it's an error to have return this; or anything similar inside the constructor.
Return statement inside a constructor doesn't logically makes sense because the purpose of the constructor is to perform initialization. The object has not been created yet, the actual construction of the object happens in JVM.
This seems to be quite a confusing question. Per the definition, I understand that constructor is a special type of method used to initialize the state of an object and/or assign values to instance variables.
Also someone in Stack Overflow mentioned that constructor returns an object (instance) of a class, as opposed to what a normal method does/returns?
Despite going through lots of tutorials and reference materials, I couldn't find a concrete reason as to how constructor is able to return a value without the presence of a return statement.
I'm curious to find out the internal working of the entire process.
Constructors don't return anything. A constructor simply initializes an instance.
A new instance creation expression
new SomeExample();
produces a reference to a new instance of the specified class
A new class instance is explicitly created when evaluation of a class
instance creation expression (§15.9) causes a class to be
instantiated.
and invokes the corresponding constructor to initialize the created instance
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then
evaluate the arguments and process that constructor invocation
recursively using these same five steps. If that constructor
invocation completes abruptly, then this procedure completes abruptly
for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass constructor invocation recursively using these
same five steps. If that constructor invocation completes abruptly,
then this procedure completes abruptly for the same reason. Otherwise,
continue with step 4.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable
initializers to the corresponding instance variables, in the
left-to-right order in which they appear textually in the source code
for the class. If execution of any of these initializers results in an
exception, then no further initializers are processed and this
procedure completes abruptly with that same exception. Otherwise,
continue with step 5.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the
same reason. Otherwise, this procedure completes normally.
It gives the JVM the 'return' opcode:
'return' returns to the calling method:
http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
Code for a default constructor:
aload_0
invokespecial #1; //Method java/lang/Object
return
A Java constructor does not return anything. A constructor simply initializes a new instance of an object of a specific class. Sometimes constructors will have System.out.Println("text") which may lead you to think it returns something, but you can have that statement in any method that doesn't have a return type.
In bytecode
Test1 t1 = new Test1();
looks as follows
NEW test/Test1 //create an uninitized instance of Test1
DUP
NVOKESPECIAL test/Test1.<init> ()V // call construcctor
STORE 1 // save reference to created instance in local var
and this is constructor, void method in fact with special name <init>
public <init>()V //V means no return value, void
L0
LINENUMBER 3 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V // call super constructor
RETURN
I used to think that, intuitively speaking, a constructor in Java is the thing that makes an object, and that nothing can touch that object until its constructor returns. However, I have been proven wrong about this over and over again:
uninitialized objects can be leaked by sharing this
uninitialized objects can be leaked by a subclass accessing it from the finalizer
uninitialized objects can be leaked to another thread before they're fully constructed
All of these facts violate my intuition of what I thought a constructor is.
I can no longer with confidence say what a constructor actually does in Java, or what it's meant to be used for. If I'm making a simple DTO with all final fields, then I can understand what the use of the constructor is, because this is exactly the same as a struct in C except it can't be modified. Other than that, I have no clue what constructors can be reliably used for in Java. Are they just a convention/syntactic sugar? (i.e If there were only factories that initialize objects for you, you would only have X x = new X(), then modify each field in x to make them have non default values - given the 3 facts above, this would be almost equivalent to how Java actually is)
I can name two properties that are actually guaranteed by constructors: If I do X x = new X(), then I know that x is an instance of X but not a subclass of X, and its final fields are fully initialized. You might be tempted to say that you know that constructor of X finished and you have a valid object, but this is untrue if you pass X to another thread - the other thread may see the uninitialized version (i.e what you just said is no different than the guarantees of calling a factory). What other properties do constructors actually guarantee?
All of these facts violate my intuition of what I thought a constructor is.
They shouldn't. A constructor does exactly what you think it does.
1: uninitialized objects can be leaked by sharing this
3: uninitialized objects can be leaked to another thread before they're fully constructed
The problem with the leaking of this, starting threads in the constructor, and storing a newly constructed object where multiple threads access it without synchronization are all problems around the reordering of the initialization of non-final (and non-volatile) fields. But the initialization code is still done by the constructor. The thread that constructed the object sees the object fully. This is about when those changes are visible in other threads which is not guaranteed by the language definition.
You might be tempted to say that you know that constructor of X finished and you have a valid object, but this is untrue if you pass X to another thread - the other thread may see the uninitialized version (i.e what you just said is no different than the guarantees of calling a factory).
This is correct. It is also correct that if you have an unsynchronized object and you mutate it in one thread, other threads may or may not see the mutation. That's the nature of threaded programming. Even constructors are not safe from the need to synchronize objects properly.
2: uninitialized objects can be leaked by a subclass accessing it from the finalizer
This document is talking about finalizers and improperly being able to access an object after it has been garbage collected. By hacking subclasses and finalizers you can generate an object that is not properly constructed but it is a major hack to do so. For me this does not somehow challenge what a constructor does. Instead it demonstrates the complexity of the modern, mature, JVM. The document also shows how you can write your code to work around this hack.
What properties are guaranteed by constructors in Java?
According to the definition, a constructor:
Allocates space for the object.
Sets all the instance variables in the object to their default values. This includes the instance variables in the object's superclasses.
Assigns the parameter variables for the object.
Processes any explicit or implicit constructor invocation (a call to this() or super() in the constructor).
Initializes variables in the class.
Executes the rest of the constructor.
In terms of your 3 issues, #1 and #3 are, again, about when the initialization of non-final and non-volatile fields are seen by threads other than the one that constructed the object. This visibility without synchronization is not guaranteed.
The #2 issue shows a mechanism where if an exception is thrown while executing the constructor, you can override the finalize method to obtain and improperly constructed object. Constructor points 1-5 have occurred. With the hack you can bypass a portion of 6. I guess it is in the eye of the beholder if this challenges the identity of the constructor.
From the JLS section 12.5:
12.5. Creation of New Class Instances
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then
evaluate the arguments and process that constructor invocation
recursively using these same five steps. If that constructor
invocation completes abruptly, then this procedure completes abruptly
for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass constructor invocation recursively using these
same five steps. If that constructor invocation completes abruptly,
then this procedure completes abruptly for the same reason. Otherwise,
continue with step 4.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable
initializers to the corresponding instance variables, in the
left-to-right order in which they appear textually in the source code
for the class. If execution of any of these initializers results in an
exception, then no further initializers are processed and this
procedure completes abruptly with that same exception. Otherwise,
continue with step 5.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly
for the same reason. Otherwise, this procedure completes normally.
**
Unlike C++, the Java programming language does not specify altered rules for method >dispatch during the creation of a new class instance. If methods are invoked that are >overridden in subclasses in the object being initialized, then these overriding methods >are used, even before the new object is completely initialized.
And from JLS 16.9:
Note that there are no rules that would allow us to conclude that V is
definitely unassigned before an instance variable initializer. We can
informally conclude that V is not definitely unassigned before any
instance variable initializer of C, but there is no need for such a
rule to be stated explicitly.
Happens before 17.4.5:
Threading 17.5.2:
A read of a final field of an object within the thread that constructs
that object is ordered with respect to the initialization of that
field within the constructor by the usual happens-before rules. If the
read occurs after the field is set in the constructor, it sees the
value the final field is assigned, otherwise it sees the default
value.
A class contains constructors that are invoked to create objects from the class blueprint.
This is what Oracle says about constructors.
Now to your point.
intuitively speaking, a constructor in Java is the thing that makes an object, and that nothing can touch that object until its constructor returns.
So according to the official documentation, your assumption is not right. And the point 1 and 2 are the abuse of the rules and behaviors of Java, unless you consciously want to leak your objects! As also being irrelevant to Constructor, I will skip discussing these points.
Now if we talk about your 3rd point, in multi-threaded environment there is nothing that can guarantee you about the consistency of your code, unless "properly synchronized blocks" or "the atomic instructions". As object creation is not a synchronized nor an atomic instruction, there is no guarantee of being consistent! There is nothing the Constructor can do with it. In other words its not the responsibility of the Constructor to make your object creation atomic.
Now, the answer to your question, "What other properties do constructors actually guarantee?" is somewhat easy. Constructors are merely nothing but special type of methods, that are invoked during object creation from the blue print of the class. So it can guarantee nothing, unless you give it a chance to be executed consistently like any other methods. It after being consistently executed it can guarantee you that, your object is created and initialized as you wanted and instructed in it.
constructors is java are just used to initialize the state of the object created..nothing more.