I was learning about using this() to call an overloaded constructor and came across this restriction:
You can not use any instance variable of the constructor's class in a call
to this()
For example:
class Test{
int x;
public Test() {
this(x); //Does not compile
}
public Test(int y) {}
void method1() {
method2(x); //OK
}
void method2(int y) {}
}
I know that no need to pass an instance field to a constructor since it's visible by default. However, why is the same restriction not applied to instance methods?
There is one other requirement in Java: constructor calls (using this() must be performed first within any constructor. The constructors will initialize the object.
After that the instance fields are initialized after these initial calls. So as the field values are now well defined, you can use them for anything including calling other methods.
However, before the initial constructor calls, the fields are in an undefined state and cannot be used as argument for other constructor calls.
For these kind of things you need to look in the JLS:
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.
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.
So the instance variables are only initialized after the constructor calls. This makes sense, because it would be strange to first assign it the default value (zero or null) and then assign it another value from within a constructor.
The constructor constructs the instance. So we shouldn't expect the instance variable x to be initialized at the time the constructor starts.
On the other hand, an instance method can already access instance variables. There is no reason to forbid passing them as a parameter into another instance method.
However, when we start to think about it a bit further, that restriction on the constructor doesn't make that much sense anymore. We are able to access instance variables there as well, so why shouldn't we be able to pass it a parameter to another constructor?
So a better question to ask is: Why can't we pass an instance variable to call an overload of our constructor from within our constructor?
And this question has been beautifully answered. It could even be considered a duplicate (but since that pretext is neccessary to understand why, I wrote an answer instead of simply flagging).
The instance fields that are declared and initialized in the class body outside of the constructor, like your int x; are assigned after the call to the overloaded constructor.
You can compare that to the other restriction we have about calling constructor overloads: We can only do so in the first line of our constructor. Right at the start. And then, the variables are not yet initialized. But they are initialized right before the first non-constructor-call instruction.
Tangential information to why this other restriction is a thing can be found here and there:
Because the JLS says so. Could the JLS be changed in a compatible manner to allow it? Yup.
Historically, this() or super() must be first in a constructor. This
restriction was never popular, and perceived as arbitrary. There were
a number of subtle reasons, including the verification of
invokespecial, that contributed to this restriction. Over the years,
we've addressed these at the VM level, to the point where it becomes
practical to consider lifting this restriction, not just for records,
but for all constructors.
You should be educating the class order initialization f.e: https://www.baeldung.com/java-initialization
The int x field is not initialized when the class constructor is called. You can set (initialize) `int x 'in your constructor, but not call it.
I don't know why you have to follow this way, but you can use the static field:
class Test{
static int x;
public Test() {
this(x); //Does not compile
}
public Test(int y) {}
void method1() {
method2(x); //OK
}
void method2(int y) {}
}
You can also initialize a static field in the line where it is called,
static int x =4/2;
or in static block:
static int x;
static {
x = 4/2;
}
Related
So I'm looking at a Java project for my university and the code we are working with has this syntax that I have never seen before:
public abstract class Machinery {
protected String name="default Computer";
protected int weight=0;
protected static int num_of_Machineries;
//int counter=0;
static String kevo=" ";
{
num_of_Machineries++;
System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
System.out.println("Machinery construction call Baby!");
print(this);
}
}
From what I understand, this works like a default constructor. Can anyone confirm or deny my suspicions?
That's an instance initializer.
It's effectively a block of code that is inlined into the start of constructors (*), rather than being a constructor itself.
Since this class has no explicit constructor, the compiler gives it a default constructor. Default constructors invoke super(), so the instance initializer is inlined into it.
It's effectively the same as:
public abstract class Machinery {
protected String name="default Computer";
protected int weight=0;
protected static int num_of_Machineries;
//int counter=0;
static String kevo=" ";
public Machinery() {
// Invoke the default super constructor.
super();
// Inline body of instance initializer.
num_of_Machineries++;
System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
System.out.println("Machinery construction call Baby!");
print(this);
// Rest of constructor body (which is empty).
}
}
Unless you have a very good reason (**) to use an instance initializer (and I'll say you don't, if you don't know what one is), it is better to define an explicit constructor and put the code from the instance initializer in there.
Note: you probably don't want to execute print(this); in the initializer/constructor: at the time this is executed, your instance isn't fully initialized, so this might have some unexpected effects.
(*) It is inlined into all constructors which (implicitly or explicitly) invoke super(...);. It is not inlined into constructors which invoke this(...);, because those have to (eventually) invoke a constructor invoking super(...);, and you only want the initializer code to be executed once.
(**) The only good reason I can think of is to avoid having to duplicate code between two or more super(...)-invoking constructors; but even then, you can often write it with methods. The only time where you really can't do it without an instance initializer is where there are multiple super(...)-invoking constructors which initialize co-dependent final fields. Rare, and probably a sign you should rethink the class.
we know that...
Instance Variable are initialized in default constructor. For eg.
public class H{
int x;
public static void main(String... args){
System.out.print(new H().x);
}
}
The O/P of above code is 0 because there is a default constructor which is called , and that constructor initialized the x to 0.
Now, my question is, if we run the below code, i.e.
public class H{
int x;
public H(){}
public static void main(String... args){
System.out.print(new H().x);
}
}
The actual O/P is 0 in this case also, but I think there should be compiler error that x is not initialized, because we have override the default constructor and didn't initialize x.I think I have made my question clear..
In Java, instance members are defaulted to the all-bits-off version of their value automatically (ints are 0, object references are null, floats are 0.0, booleans are false, and so on). It's not something the default constructor does, it's done before the constructor runs.
The order is:
Default the instance members to their all-bits-off value. (The optimizer can skip this if it sees #2 below or possibly if it can prove to itself that nothing uses the member prior to an initialization per #3 below.)
Apply any inline initialization of them. For instance:
int a = 42;
Apply instance initialization blocks in source code order.
Call the appropriate constructor.
So for example:
class Example {
int a = 42;
// Instance initializer block:
{
this.a = 67;
}
Example() {
System.out.println(this.a);
}
}
new Example() outputs 67.
Obviously, initializing in both places like that would be poor practice, this is just for illustration.
Non-final fields are initialized by default in java. Only variables inside methods and final fields are not initialized by default.
If you had declared x to be final, then you would be correct. You would have a compile error in the code.
All instance level variables are initialized to their default values irrespective of whether the constructor has been overloaded ( or explicit no-argument constructor has been added). The constructor merely changes the default value(s).
Instance variables have default values associated with them
From The Java™ Tutorials:
Default values
It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type.
Java is quite neat to programmers (unlike others, C for instance), this means that it initializes fields automatically. An exception is final fields and fields inside a methods (where the compiler will then produce an error).
Hope it helped.
Is there any difference between these two ways of initialising class members?
In the class body:
public class A {
private mB = new B();
public A() {
}
}
Or in the constructor:
public class A {
private mB = null;
public A() {
mB = new B();
}
}
In theory, there is a difference in the sequence of initialization. This is the sequence used by the JVM:
Static statements/static blocks are executed.
Instance variables are assigned default values
Instance variables are initialized if the instance variable is assigned a compile time constant. Otherwise, it will be done with Item 5 (instance variables and instance initializers will be done together from the top to the bottom, in the order they are defined).
constructor runs
Instance initialization block(s) run after all the call(s) to super has(have) been completed but before the rest of the constructor is executed.
Rest of the constructor is executed.
Also, if you initialize the fields in the constructor, it can mean that you might get some duplication. Personally, I think it doesn't matter much where you instantiate them, either in the constructor or in the fields, but the main point is that you are consistent about it. For me it helps having them instantiated in the field declaration so I know which fields are always there, and which fields are optional. Hope that helps!
The instance initializer run first and then values in constructor are initialized. You can study order of execution of initialization blocks and constructors
If B() constructor threw a checked exception then this
private mB = new B();
would be a compile time error, while in constructor you could catch it or declare in throws clause
I would do the one you believe is simpler.
The main difference is that if you add another constructor to the first, you don't have to repeat the initialisation.
Your first example initializes the variable once: your second example, twice. First is to be preferred, especially if there are multiple constructors, unless there is an exception involved of course.
As per standard book constructor is a special type of function which is used to initialize objects.As constructor is defined as a function and inside class function can have only two type either static or non static.My doubt is what constructor is ?
1.)As constructor is called without object so it must be static
Test test =new Test();//Test() is being called without object
so must be static
My doubt is if constructor is static method then how can we frequently used this inside
constructor
Test(){
System.out.println(this);
}
Does the output Test#12aw212 mean constructors are non-static?
Your second example hits the spot. this reference is available in the constructor, which means constructor is executed against some object - the one that is currently being created.
In principle when you create a new object (by using new operator), JVM will allocate some memory for it and then call a constructor on that newly created object. Also JVM makes sure that no other method is called before the constructor (that's what makes it special).
Actually, on machine level, constructor is a function with one special, implicit this parameter. This special parameter (passed by the runtime) makes the difference between object and static methods. In other words:
foo.bar(42);
is translated to:
bar(foo, 42);
where first parameter is named this. On the other hand static methods are called as-is:
Foo.bar(42);
translates to:
bar(42);
Foo here is just a namespace existing barely in the source code.
Constructors are non-static. Every method first parameter is implicit this (except static) and constructor is one of that.
Constructors are NOT static functions. When you do Test test =new Test(); a new Test object is created and then the constructor is called on that object (I mean this points to the newly created object).
The new keyword here is the trick. You're correct in noting that in general, if you're calling it without an object, a method is static. However in this special case (i.e., preceded by the new keyword) the compiler knows to call the constructor.
The new operator returns a reference to the object it created.
new Test(); // creates an instance.
The System.out.println(this); is called after the new operator has instantiated the object
Not static. Read about constructors http://www.javaworld.com/jw-10-2000/jw-1013-constructors.html.
Neither.
Methods can be divided into 2 types: static/non-static methods, aka class/instance methods.
But constructors are not methods.
When we talk about static class then it comes to our mind that methods are called with class name,But in case of constructor ,Constructor is initialized when object is created So this proves to be non-static.
Constructors are neither static (as called using class name) or non-static as executed while creating an object.
Static:
Temp t= new Temp();
The new operator creates memory in the heap area and passes it to the constructor as Temp(this) implicitly. It then initializes a non-static instance variable defined in a class called this to the local parameter variable this.
Below example is just for understanding the concept, if someone tries to compile it, it will give the compile-time error.
class Temp{
int a;
Temp this; //inserted by compiler.
Temp(Temp this){ //passed by compiler
this.this=this; // initialise this instance variable here.
this.a=10;//when we write only a=10; and all the non-static member access by this implicitly.
return this; // so that we can't return any value from constructor.
}
}
Constructor is static because:
It is helping to create object.
It is called without object.
Constructor is used to initialize the object and has the behavior of non-static methods,as non-static methods belong to objects so as constructor also and its invoked by the JVM to initialize the objects with the reference of object,created by new operator
I have a class
public class MyMain{
public static void main(String... arg){
Temp t = new Temp(){
{
System.out.println(" instance initialize");
}
};
}
}
class Temp{
int i;
{
i=9;
System.out.println("Static"+i);
}
Temp(){
System.out.println("Temp const "+i);
}
}
When i execute the main method the output comes:
Static9
Temp const 9
instance initialize
Ideally, the blocks are executed before the constructor, but the inline initialization block is called after the Constructor. Why?
You're creating a subclass of Temp. For each class, any instance initializers are executed before the constructor body - but the superclass goes through initialization before the subclass initialization. So the execution flow is:
Initializers in Object
Constructor body in Object
Initializers in Temp
Constructor body in Temp
Initializers in anonymous class
Constructor body in anonymous class (none)
I would strongly advise you to refactor any code which looked like this anyway - aim for clarity rather than cleverness.
JLS 12.5 spells out the order in which things happen during construction (emphasis mine):
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:
(3) 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.
(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.
(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.
To summarize, superclass constructors (step 3) are executed before instance initializers (step 4). Both are executed before "the rest of the body of this constructor" (which you don't have in your example).
The inline initialisation block is called after the constructor of the base class of the anonymous class you are instancing at the moment and before the empty implicit constructor of the anonymous class itself.
What you are actually creating is not a Temp class instance, but an instance of some anonimous class, that inherits from Temp.
Thus, at first, the Temp initializers are called (anonimous block inside Temp and its construstor) and initializers in anonimous class are called afterwards.
In your code
Temp t = new Temp(){
{
System.out.println(" instance initialize");
}
};
you are creating object of anonymous class which extends Temp class.
Creating object of Subclass:
initialize block from Superclass
constructor of Superclass
initialize block from Subclass
constructor of Subclass
Point 1: To be clear, you have two instance initializers: one in the Temp class and one in the anonymous inner class created in the main() method that is a subclass of Temp.
Point 2: Instance initializers aren't actually run before constructors. Per the JLS, they're run during a constructor, after delegating to the super constructor and before initializing instance fields and completing the constructor.
Point 3: In your code, each initializer is correctly executed at its appropriate time. I think you're expecting the second one to execute at the same time as the first one, but that would be incorrect because as pointed out in Point 1, they're initializers for two different classes.
Point 4: You may also be confused between static initializers and instance initializers. They're two distinct things.
The object must be in memory first before anything else can be done to it. The object is constructed in memory and then your console prints happen.