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.
Related
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.
I have seen a few questions on the topic, but they all assume knowledge of inheritance. The example in my book is before the inheritance chapter, so the parent class is java.long.Object.
1. Scenario: my class FotoApparat has no custom constructor or any constructor at all and I create an instance of FotoApparat with FotoApparat meinFotoApparat = new FotoApparat()
Question: As my class has no constructor and also no super() call, I assume the program checks the parent Object class for a suitable constructor, which should be new Object(), right? If yes, is this still considered an "implicit" super() call?
2. Scenario: I create a custom constructor (by using eclipse source) which takes on parameters. In the generated constructor the super() call is added in the very beginning, which I assume is the actual implicit call I keep reading about. I read on javapoint that when an instance of a class is created, an instance of the parent class is also created, which is referenced by super().
Question: I read that this super() call can be removed from the constructor, but if it is removed and I use a constructor that takes on parameters, then (without super()) how is this parent object created ?!
Scenario 1:
If you don't define any constructor, a default, no-argument, constructor is created for you. That's the one that is called when using new FotoApparat(). This default constructor then calls the constructor on Object (see scenario 2.)
Scenario 2:
If you don't explicitly call super(), this call is still done implicitly. It is possible however that the parent object does not have a constructor without arguments, in which case you are required to call a specific constructor.
As my class has no constructor and also no space() call, I assume the program checks the parent Object class for a suitable constructor
Not quite. If you don't define a constructor, the compiler creates one for you. This constructor takes no arguments, and the only thing it does is call the super class constructor super().
when an instance of a class is created, an instance of the parent class is also created
Not quite: only one instance is created. There is no separate parent class instance.
The statement is not entirely incorrect because thanks to inheritance, the one instance of the child class that is created is also an instance of the parent class.
I read that this super() call can be removed from the constructor, but if it is removed and I use a constructor that takes on parameters, then (without super()) how is this parent object created ?!
In this scenario the compiler inserts a call to the no-argument super class constructor super(). But this does not create a separate "parent object" - only one object is created.
What your studies may not have made clear is the distinction between object creation and initialization. Calling a constructor does not "create" an object. An object is created by reserving space for it in memory. After the memory has been reserved, the constructor is called to "initialize" the object.
I've one doubt about java reference type creation.
Suppose I've one class below
public class DefaultRepositorySelector
implements RepositorySelector
{
final LoggerRepository repository;
public DefaultRepositorySelector(LoggerRepository repository)
{
this.repository = repository;
}
public LoggerRepository getLoggerRepository()
{
return this.repository;
}
}
And am calling above class's constructor DefaultRepositorySelector somewhere in another class, like below.
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
As you can see am Initializing a class new DefaultRepositorySelector(new NOPLoggerRepository()) and constructor accepts NOPLoggerRepository instance which is having an implementation of LoggerRepository Interface.
My doubt here is, we are directly passing a new NOPLoggerRepository() as a parameter in constructor which is an instance not a reference type, But constructor is holding a reference type LoggerRepository.
Am not able to understands the flow here, because according to flow when we are creating an instance we passing new object but not a reference to that object but in class's definition constructor accepts reference type of that object.
So at run time, How its taken care when we directly pass an instance but method or constructor accepts reference type of that instance ? Who gets created first reference type of OR Instance ? I think reference type but am not sure how its working behind the scenes..!
My question sounds very silly but please help to understand this ..!
Thanks
An object of class NOPLoggerRepository is created and passed to the method.
That's valid because NOPLoggerRepository implements LoggerRepository.
Rules about when an object is no longer reachable (and available for garbage collection) mean it won't be collected before being passed in (in case you were worrying about such weirdness).
When the constructor has completed the DefaultRespositorySelector holds a reference to the object passed in. However we know (in this case) it's underlying class is NOPLoggerRepository.
All good. The compiler knows when the underlying type may not be the explicit type of a reference and by various mechanisms ensures the correct behaviour. (Glossing over a whole load of stuff some implementation defined).
In java you never 'really' pass a object and class variables don't hold 'objects'.
They are always references to objects.
In casual conversation we all often say things like "I'm passing an NOPLoggerRespository to the constructor" but we really mean I'm passing a reference to a NOPLoggerRespository to the constructor. That's OK because it's always a reference so long as we all understand it's a fine shorthand.
I'm not quite sure I correctly understand your question.
You are going to create the object with the name repositorySelector of type DefaultRepositorySelector. While calling the constructor you need to have a reference of a LoggerRepository, which is a reference to a existing object (or null, if you pass null).
So, to get a reference, you pass new NOPLoggerRepository().
The expressions in parenthesis are evaluated first, so before the constructor of DefaultRepositorySelector can be called, the NOPLoggerRepository will be created as an anonymous object. That is, the object is created and is given no name. But we have the reference to it, which means we know where it is located on the heap.
As NOPLoggerRepository is of type LoggerRepository the constructor of DefaultRepositorySelector accepts the reference - the location of the anonymous object located on the heap and the object, which is named repositorySelector will be created.
Long story short, before calling a method (or constructor) the parameters are evaluated first (object creation, mathematical calculations, other method called and evaluated etc.), then the actual method can be called with the evaluated arguments.
The general idea of
Java is pass by Value
in objects does pretty much varie from premitive types .
in your code :
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
the (new NOPLoggerRepository() is considered an Ignored Instance for the code scope in wich is invoked .
the thing in here is when you invoked the new DefaultRepositorySelector it did nothing at first as the parameters are invoked first , so in the ordered sequence
new NOPLoggerRepository() is invoked and created a new instance with no refrence on it on the heap .
new DefaultRepositorySelector is invoked and do ask for it's RepositorySelector instance wich is located with no any refrence in the example .
the JVM create the sole refrence for that object in your constructor and then another one (when your constructer pops off) in your class a .
so in short . it is still by refrence but just behind the scene .
What you're referring to is commonly known as dependency injection. First, the object that's being injected is instantiated, and then the dependent object. SO answer here.
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.
Please refer to the Java code below:
class Base{
Base(){
System.out.println("Base Constructor");
method();
}
void method(){}
}
class Derived extends Base{
int var = 2;
Derived(){
System.out.println("Derived Constructor");
}
#Override
void method(){
System.out.println("var = "+var);
}
}
class Test2{
public static void main(String[] args) {
Derived b = new Derived();
}
}
The output seen is:
Base Constructor
var = 0
Derived Constructor
I think var = 0 occurs because Derived object is half initialized; similar to what Jon Skeet says here
My questions are:
Why does the overridden method get called if the Derived class object isn't created yet?
At what point in time is var assigned value 0?
Are there any use cases where such behavior is desired?
The Derived object has been created - it's just that the constructor hasn't been run yet. The type of an object never changes in Java after the instant it is created, which happens before all constructors run.
var is assigned the default value of 0 as part of the process of creating an object, before constructors are run. Basically, the type reference gets set and the rest of the memory representing the object gets wiped to zero (conceptually, anyway - it may already have been wiped to zero before, as part of garbage collection)
This behaviour at least leads to consistency, but it can be a pain. In terms of consistency, suppose you had a read-only subclass of a mutable base class. The base class may have an isMutable() property which was effectively defaulted to true - but the subclass overrode it to always return false. It would be odd for the object to be mutable before the subclass constructor ran, but immutable afterwards. On the other hand, it's definitely strange in situations where you end up running code in a class before the constructor for that class has run :(
A few guidelines:
Try not to do much work in a constructor. One way of avoiding this is to do work in a static method, and then make the final part of the static method a constructor call which simply sets fields. Of course, this means you won't get the benefits of polymorphism while you're doing the work - but doing so in a constructor call would be dangerous anyway.
Try very hard to avoid calls to non-final methods during a constructor - it's very likely to cause confusion. Document any method calls you really have to make very clearly, so that anyone overriding them knows that they will be called before initialization has finished.
If you have to call a method during construction, it's usually not then appropriate to call it afterwards. If that's the case, document it and attempt to indicate it in the name.
Try not to overuse inheritance in the first place - this is only going to become an issue when you've got a subclass deriving from a superclass other than Object :) Designing for inheritance is tricky.
Why does the overridden method get
called if the Derived class object
isn't created yet?
Derived class constructor implicitly calls the Base class constructor as the first statement. Base class constructor calls method() which invokes the overridden implemention in the Derived class because that is the class whose object is being created. method() in Derived class sees var as 0 at that point.
At what point in time is var assigned
value 0?
var is assigned the default value for int type i.e. 0 before the contructor of Derived class is invoked. It gets assigned the value of 2 after the implicit superclass contructor call has finished and before the statements in Derived class's constructor start executing.
Are there any use cases where such
behavior is desired?
It is generally a bad idea to use non-final non-private methods in the constructors/initializers of a non-final class. The reasons are evident in your code. If the object that is being created is a subclass instance, the methods may give unexpected results.
Note that this is different from C++, where the type does change while the object is being constructed, so that calling a virtual method from the base class constructors doesn't call the derived class's override. The same thing happens in reverse during destruction. So this can be a small trap for C++ programmers coming to Java.
There are some properties of the Java language specification that should be noted in order to explain this behavior:
A superclass' constructor is always implicitely/explicitely called before a subclass' constructor.
A method call from a constructor is just like any other method call; if the method is a non-final, then the call is a virtual call, meaning that the method implementation to invoke is the one associated with the runtime type of the object.
Prior to a constructor execution, all data members are automatically initialized with default values (0 for numeric primitives, null for objects, false for boolean).
The sequence of events is as follows:
An instance of the subclass is created
All data members are initialized with default values
The constructor being invoked immediately delegates control to the relevant superclass' constructor.
The super constructor initializes some/all of its own data members, and then calls a virtual method.
The method is overriden by the subclass, so the subclass implementation is invoked.
The method tries to use the subclass' data members, assuming they are already initialized, but this is not the case - the call stack hasn't returned to the subclass' constructor yet.
In short, whenever a constructor of a superclass invokes a non-final method, we have the potential risk of entering into this trap, therefore doing it is not recommended.
Note that there is no elegant solution if you insist on this pattern. Here are 2 complex and creative ones, both requiring thread synchronization(!):
http://www.javaspecialists.eu/archive/Issue086.html
http://www.javaspecialists.eu/archive/Issue086b.html