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?
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.
Related
I have difficulty in using a generated bytecode class which is loaded by Unsafe.defineAnonymousClass(). I am wondering how to use an object of anonymous class to initiliaze another class (or anonymous class).
Take an example class Callee below for example, its constructor accepts Callee2 as parameter.
Class Callee{
Callee2 _call2;
public Callee(Callee2 callee2){
...
}
}
During runtime, I generated new classes for both Callee2 and Callee, and both new classes are loaded by Unsafe.defineAnonymousClass(). For new Callee, the constructor is also changed to be:
public test.code.jit.asm.simple.Callee(test.code.jit.asm.simple.Callee2.1506553666);
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: aload_0
1: invokespecial #65 // Method java/lang/Object."<init>":()V
....
8: return
while the generated class name of Callee2 is:
class test.code.jit.asm.simple.Callee2/1506553666
I created an instance of `Callee2/1506553666' and want to create instance of new Callee with it, but fail:
newCls.getConstructor(args).newInstance(objs);
where
args = [class test.code.jit.asm.simple.Callee2/1506553666]
and
objs= [test.code.jit.asm.simple.Callee2/1506553666#39b0a038]
The args[0] is meanless as this class is loaded by anonymous loader (Anonymous classes are not referenced by any class loaders). So it really puzzles me how to pass objects in objs array to a method invocation..
The exception occurs on the invocation of getConstructor (args) with message:
java.lang.NoClassDefFoundError: test/code/jit/asm/simple/Callee2/1506553666
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2483)
at java.lang.Class.getConstructor0(Class.java:2793)
at java.lang.Class.getConstructor(Class.java:1708)
at code.jit.asm.util.ReflectionUtil.adapt2GeneratedObject(ReflectionUtil.java:36)
at code.jit.asm.services.BytecodeGenerator.generator(BytecodeGenerator.java:164)
The exception is clearly for me since the anonymous class is transient to any classloader. But in my case, I do need initialize the new Callee (also anonymous class) by new Callee2 instance (The bytecodes in Callee's constructor will reads Callee2's field members), so is there any workaround to pass new callee2 instance for the new callee's constructor?
Have a look at the signature and documentation comment, which is not available in the standard API documentation as it’s not part of the official API:
Define a class but do not make it known to the class loader or system dictionary.
For each CP entry, the corresponding CP patch must either be null or have the a format that matches its tag:
Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
Utf8: a string (must have suitable syntax if used as signature or name)
Class: any java.lang.Class object
String: any object (not just a java.lang.String)
InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
… (params:)
cpPatches where non-null entries exist, they replace corresponding CP entries in data
public native Class<?> defineAnonymousClass(
Class<?> hostClass, byte[] data, Object[] cpPatches);
In other words, you may provide an array of the same size as the constant pool of the class you’re going to define. Keep nulls where you don’t want to modify it. Right at the places where your constant pool has a CONSTANT_Class_info representing an anonymous class, you simply pass the associated Class object in the array. So there’s no lookup for the class then, you don’t even have to provide the correct class name in the class bytes.
There are some obvious limitations:
Problem will arise if you have circular dependencies as you need an already existing Class object to patch the pool of another class. Well, for class uses that are known to be resolved lazily, it might work
You can only patch CONSTANT_Class_info to a Class which is sufficient for, e.g. accessing members of that class or creating new instances of it. But it doesn’t help when an anonymous class is part of a signature, i.e. you want to declare a field of that type or use a method having it as parameter or return type. But you may access such methods using the option of patching a CONSTANT_InterfaceMethodref_info entry via a MethodHandle (ahem, once implemented as I guess “NYI” means “not yet implemented”)…
I understand that there are three parts to object creation:
Declaration
Instantiation
Initialization
classA{}
classB extends classA{}
classA obj = new classB(1,1);
Instantiation
It has to create an object using new operator
and this object must have all the fields related to classB (initialized to default values does this step give a call to default constructor?) this is instantiation
does it mean this step is initialization using java's default constructor?
Initialization
this object is then passed down the hierarchy giving calls to various constructor in the way to get initialized (which comes under initialization)
and the final obj is created by 'classB(1,1)` constructor whith required Initializations
but how is the object mentioned in instantiation step being created initially with all available fields?
please point out if anything i said is wrong
If the class has no constructor a default constructor is implicitly defined.
Constructors have method name <init> in a stacktrace.
A constructor call does the following:
the object is created, with all fields nulled: 0, 0.0, null, ...
the super constructor is called, possibly implicit if not present in the code.
all initialized fields (A a = ...;) are initialized by doing the assignments.
the rest of the constructor is executed.
Roughly, the way it works is:
The new bytecode instruction is executed with a symbolic reference to the class of the object to be created. As described in the Java Virtual Machine Specification, this allocates a new object in the garbage collected heap and initializes all fields to their default values.
One of the object's constructors is called. (Which one is called depends on what was coded.) All constructors (except for Object itself) must, as their first step, call another constructor in the same class or call a constructor in the superclass. (If you don't code one of these calls in a constructor, the compiler automatically inserts a call to super();—the default superclass constructor—at the start of that constructor. Each constructor in the chain—starting with Object at the deepest level of constructor calls—does whatever setting of instance fields in the object.
The second step might be modified slightly if there are instance initializers in the class declaration. See Chapter 8 of the Java Language Specification for details.
I have writen the small java class which I want to load by using ClassLoader.
public class ClassLoadingObj {
public ClassLoadingObj(){
System.out.println("---instantiating ClassLoadingObj ");
}
static{
System.out.println("---Loading ClassLoadingObj");
}
}
But when I executed the following code:
ClassLoader.getSystemClassLoader().loadClass("com.st.classLoader.ClassLoadingObj");
I find that the static block does not get executed. My question is that if a class is loaded by using the loadClass() method, why are static blocks not executed in comparison to instantiating a class where static blocks always get executed.
Actually static block gets executed when the class is initialized and it's a little bit different from loaded.
Before initialized class is linked and before that it is loaded, so there are 3 (or 4, including not-loaded) states of class.
Here is well described how it works and what are the requirements for a class to become initialized.
An excerpt:
The Java virtual machine specification gives implementations
flexibility in the timing of class and interface loading and linking,
but strictly defines the timing of initialization. All implementations
must initialize each class or interface on its first active use. The
following six situations qualify as active uses:
A new instance of a class is created (in bytecodes, the execution of a new instruction. Alternatively, via implicit creation,
reflection, cloning, or deserialization.)
The invocation of a static method declared by a class (in bytecodes, the execution of an invokestatic instruction)
The use or assignment of a static field declared by a class or interface, except for static fields that are final and initialized
by a compile-time constant expression (in bytecodes, the execution
of a getstatic or putstatic instruction)
The invocation of certain reflective methods in the Java API, such as methods in class Class or in classes in the
java.lang.reflect package
The initialization of a subclass of a class (Initialization of a class requires prior initialization of its superclass.)
The designation of a class as the initial class (with the main()< method) when a Java virtual machine starts up
There are two types of class loader in java. Maybe the ClassLoader you use is the
java.lang.ClassLoader, but the system won't use the this ClassLoader. You can try
com.sun.org.apache.bcel.internal.util.ClassLoader.getSystemClassLoader(), it will execute
the static block. More information you can reference to this
page (http://en.wikipedia.org/wiki/Java_Classloader#Class_Loaders_in_JEE)
I had a test today and one of the questions was about using a virtual method in C++ constructor. I failed this question, I answered that there shouldn't be any problem, however after reading this I found out I was wrong.
So I understand that the reason for not allowing that is because the derived object is not fully initialized and therefore calling it's virtual method can cause invalid consequences.
My question how was it solved in Java/C# ? I know that I can call derived method in my base constructor, I would assume that these languages have exactly the same problem.
Java has a very different object model from C++. In Java, you cannot have variables which are objects of class type -- instead, you can only ever have references to objects (of class type). Therefore, all members of a class (which are only references) start out trivially as null until the entire derived object has been set up in memory. Only then do the constructors run. Thus by the time a base constructor calls a virtual function, even if that function is overridden, the overridden function can at least correctly refer to members of the derived class. (Those members may not themselves be assigned yet, but at least they exist.)
(If it helps, you can also consider that every class without final members in Java is technically default-constructible, at least in principle: Unlike in C++, Java has no such things as constants or references (which must be initialized in C++), and in fact there are no initializer lists at all. Variables in Java simply don't need to be initialized. They're either primitives which start as 0, or class type references which start as null. One exception comes from non-static final class members, which cannot be rebound and must actually be "initialized" by having precisely one assignment statement somewhere in every constructor [thanks to #josefx for pointing this out!].)
understand that the reason for not allowing that is because the derived object is not fully initialized and therefore calling it's virtual method can cause invalid consequences
Wrong. C++ will call the base class's implementation of the method, not the derived class's. There are no 'invalid consequences'. The only valid reason for avoiding the construct is that the behavior sometimes comes as a surprise.
This is different from Java because Java calls the derived class's implementation.
In C++ every polymorphic class( class that has at least one virtual function ) has a hidden pointer at start of it( usually named v-table or something like that ) that will be initialized to the virtual table( an array of functions that point to the body of each virtual function ) of that class and when you call a virtual function C++ simply call ((v-table*)class)[index of your function]( function-parameters ), so if you call a virtual function in base class constructor v-table point to virtual table of the base class since your class is base and it still need some initialization to become child and as a result you will call implementation of the function from base not from child and if this is a pure virtual function you will get an access violation.
but in java this is not something like this, in java whole the class is something like std::map<std::string, JValue> in this case JValue is some variant type( for example a union or boost::variant ) when you call a function in constructor of base it will find function name in the map and call it, it is still not the value from the child but you can still call it and if you changed it in the prototype, since prototype created before your constructor you can successfully call function from child but if function required some initialization from constructor of the child you still get error or an invalid result.
so in general it is not a good practice to call a function from child( for example a virtual function ) in base class. if your class need to do this add an initialize method and call it from constructor of your child class.
Every Java constructor looks like this:
class Foo extends Bar {
Foo() {
super(); // creates Bar
// do things
}
}
So if you place code working on derived methods in do things, seems to be logic, that this base object was initialized properly, after calling its constructor in super();
I think that Java/C# avoid this problem by constructing from derived class backwards rather than in C++ from base class forwards.
Java implicitly calls super() in a classes constructor so by the time the first line of written code in a derived class constructor is called all the constructors of all inherited classes are guaranteed to have been called and so the new instance will have been completely initialised.
I think also in C++ a new instance of a class begins life as the base class and gets "upgraded" to the final class type as we move down the inheritance chain. This means that when you call a virtual function in the constructor you'll actually be calling the version of that function for the base class.
In Java and presumably C# a new instance starts life as the required class type so the correct version of the virtual method will be called.
Java does not entirely avoid the problem.
An overridden method called from a superclass constructor that depends on fields of the subclass will be called before those fields have been initialized.
If you're in control of the entire class hierarchy, you can of course just make sure your overrides don't depend on subclass fields. But it's safer to just not call virtual methods from constructors.
Imagine a Java class which has most features that you can find in a class. For example: it inherits from another class, implements a couple of interfaces, includes some 'static final' constants, some final constants, some static variables, instance variables, a static block, an unnamed code block (just code in {}), constructors, methods etc.
When the class in question is loaded into the JVM for the first time, in what order are the various portions of the class initialized or loaded into the JVM? What does the call stack in the JVM look like for the loading? Assume that only one classloader is at work here.
This is going back to the absolute basics/internals of Java, but I havent been able to find a good article explaining the correct sequence.
This could be described in the section 2.17.4 of the JVMS 5.0/6
2.17.4 Initialization
Initialization of a class consists of:
executing its static initializers (§2.11) and
the initializers for static fields (§2.9.2) declared in the class.
Initialization of an interface consists of executing the initializers for fields declared in the interface (§2.13.3.1).
Before a class or interface is initialized, its direct superclass must be initialized, but interfaces implemented by the class need not be initialized. Similarly, the superinterfaces of an interface need not be initialized before the interface is initialized.
A class or interface type T will be initialized immediately before one of the following occurs:
T is a class and an instance of T is created.
T is a class and a static method of T is invoked.
A nonconstant static field of T is used or assigned. A constant field is one that is (explicitly or implicitly) both final and static, and that is initialized with the value of a compile-time constant expression. A reference to such a field must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization.
Invocation of certain methods in library classes (§3.12) also causes class or interface initialization. See the Java 2 platform's class library specifications (for example, class Class and package java.lang.reflect) for details.
The intent here is that a type have a set of initializers that put it in a consistent state and that this state be the first state that is observed by other classes. The static initializers and class variable initializers are executed in textual order and may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope. This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.
Before a class or interface is initialized its superclass is initialized, if it has not previously been initialized.
The updated version of Initialization in JVMS 8 is in Chapter 5.5
Initialization of a class or interface consists of executing its class or interface initialization method (§2.9).
A class or interface may be initialized only as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references the class or interface (§new, §getstatic, §putstatic, §invokestatic).
All of these instructions reference a class directly or indirectly through either a field reference or a method reference.
Upon execution of a new instruction, the referenced class or interface is initialized if it has not been initialized already.
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
The first invocation of a java.lang.invoke.MethodHandle instance which was the result of resolution of a method handle by the Java Virtual Machine (§5.4.3.5) and which has a kind of 2 (REF_getStatic), 4 (REF_putStatic), 6 (REF_invokeStatic), or 8 (REF_newInvokeSpecial).
Invocation of certain reflective methods in the class library (§2.12), for example, in class Class or in package java.lang.reflect.
The initialization of one of its subclasses.
Its designation as the initial class at Java Virtual Machine start-up (§5.2).
Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved.
Because the Java Virtual Machine is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time.
There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface.
The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure.
It assumes that the Class object has already been verified and prepared, and that the Class object contains state that indicates one of four situations:
This Class object is verified and prepared but not initialized.
This Class object is being initialized by some particular thread.
This Class object is fully initialized and ready for use.
This Class object is in an erroneous state, perhaps because initialization was attempted and failed.
How about the JLS, specifically section 12.4?