I'm wondering what is happening here:
I have abstract superclass
public abstract class Superclass {
public Superclass()
{
doSth();
}
public abstract void doSth();
}
And subclass
public class Subclass extends Superclass{
private int x = 10;
public void doSth()
{
System.out.println("Value x="+this.x);
}
}
When I make
Subclass x= new Subclass();
x.doSth();
I get:
Value x=0
Value x=10
I don't know why first I get x=0 (why not x=10 from the start?) and then x=10?
The constructor of the super-class is executed before the isntance initializer expressions of the sub-class, which is why x still has the default value of 0 in the first call to doSth(). The second call x.doSth() takes places after the Subclass instance is fully initialized, so x contains 10.
More details :
When you call the constrcutor of Subclass, first it calls the constructor of Superclass which calls the constructor of Object. Then the body of the Superclass constructor is executed, so doSth() is executed. Only after the Superclass constructor is done, the instance initialization expressions of Subclass (in your case, the assignment x = 10; are evaluated. Before they are evaluated, x still contains the default value - 0, which is the value you see printed by the first call to doSth().
Related
This question already has answers here:
Difference between "this" and"super" keywords in Java
(9 answers)
Closed 4 years ago.
I am trying to find proof for the statement - keyword super is the reference to parent class just like keyword this is the reference to current class.
I am trying multilevel Inheritance in Java A->B->C: class A is grand parent, class B is parent, class C is child.
I have a variable X declared in all three classes with values respectively (A:x=100,B:x=200,C:x=300)
In the child class constructor I am printing values. However the casting isn't working for super keyword whereas it's working for this keyword.
((A)super).x is not working, but ((A)this).x is working.
class A {
int x = 100;
}
class B extends A {
int x = 200;
}
public class C extends B {
int x = 300;
public C () {
System.out.println(this.x); //OP = 300
System.out.println(super.x); // OP = 200
System.out.println(((A)this).x);// OP = 100
System.out.println(((A)super).x); // Giving Compile time Error.. Why?
B reftoB = new B();
System.out.println(((A)reftoB).x); // OP = 100
}
public static void main(String[] args) {
C t1= new C();
}
}
I expect the output of System.out.println(((A)super).x) is 100, but it is giving a compile time error.
So my question is if super is a reference to the parent class then why isn't type casting working on it?
Use of Super Keyword:
super() can be used to refer immediate parent class instance
variable.
super() can be used to invoke immediate parent class method.
super() can be used to invoke immediate parent class constructor.
Your compiler is a compilation error for (A)super).x , because it is not a valid statement, moreover we don't use it this way, ontop of all It violates encapsulation, you should not able to bypass parent class. In every definition of super() you will find something mentioned as current parent class, but what you are trying to do here is bypassing current parent.
Now coming to your problem:
x // Field x in class C
this.x // Field x in class C
super.x // Field x in class B
((B)this).x // Field x in class B
((A)this).x // Field x in class A
super.super.x // Illegal; does not refer to x in class A
((A)super).x // Illegal as well as compilation error
If you still want to access variables like what you intented then use something like below:
t1.x // Field x of class C
((B)t1).x // Field x of class B
((A)t1).x // Field x of class A
Note: t1 is your class C instance.
The answer to why this can be cast but super cannot is the same answer to the question why this can be passed as a method argument but super cannot: namely, because this is defined by the JLS as a Primary Expression but super is not.
The super keyword refers to a class parent, and this keyword refers to the class you are in. Let's create a parent class to start the demonstration:
public class ParentClass{
private int justANumber;
public ParentClass(int justANumber){
this.justANumber = justANumber;
}
}
Notice how the this keyword is used here, which is telling "Hey, assign the justANumber value to THIS class attribute also called justANumber". Let's create a subclass for this parent class now:
public class Subclass extends ParentClass{
// You don't need to declare the justANumber variable, cause it's from the parent
public Subclass(int justANumber){
super(justANumber);
}
public showNumber(){
return this.justANumber;
}
}
The super() method calls the parent constructor, which need an int value on the first place, so you pass it as an argument. Now see how the showNumber() method returns this.justANumber? Why? that's because when the super() method is called, the parent class automatically delegates his variables to the subclass, so in this case, Subclass can now say that justANumber is HIS variable, being able to use the this keyword. Hope you now understand de difference.
This concept contradicts the concept of a class and it's instance.
Below is the program that looks fine to me and gives NullPointerException as expected:
class SuperClass{
int x = 2;
}
class SubClass extends SuperClass{
int x = 4;
}
public class Dummy2 {
public static void main(String[] args){
SubClass obj1 = new SubClass();
SuperClass obj2 = null;
System.out.println(obj1.x);
System.out.println(obj2.x);
}
}
But when I say SuperClass obj2 = obj1; strangely I see the value of SuperClass instance member value 2,
despite there is no instance of class SuperClass created in the above program.
Is this the valid concept in Java?
First, since obj2 is null in your example, it will of course throw a NPE when you attempt to access x in it.
Second, when you set obj2 = obj1, you are casting obj1, of type SubClass, to type SuperClass. When you then access x in obj2, you are accessing the x that SuperClass knows about, which has a value of 2. This is how it is supposed to work.
The reason is, the x in SubClass isn't overwriting the x in SuperClass. It is simply hiding it. So when obj1 is cast to type SuperClass, the x in SuperClass is now the visible x.
If you wish to get the x value that you seem to be expecting, simply use a getter instead of accessing x directly, and then you can override it in SubClass.
SuperClass:
public class SuperClass {
public int x = 2;
public int getX() {
return x;
}
}
SubClass:
public class SubClass extends SuperClass {
public int x = 4;
public int getX() {
return x;
}
}
test code:
SubClass obj1 = new SubClass();
SuperClass obj2 = obj1;
System.out.println(obj2.x); // outputs 2
System.out.println(obj2.getX()); // outputs 4
It's valid in java, and many other languages strongly typed. When you upcast the variable to a superclass you can use properties of that class only. This make a variable strongly typed. Means that you have a variable of the type that you can use regardless of instance type. The type of variable is important that you have access to.
The code is like this :
class Base {
int x = 10;
public Base() {
this.printMessage();
x = 20;
}
public void printMessage() {
System.out.println("Base.x = " + x);
}
}
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
public void printMessage() {
System.out.println("Sub.x = " + x);
}
}
public class DispatchTest {
public static void main(String[] args) {
Base b = new Sub();
System.out.println(b.x);
}
}
The result is :
Sub.x = 0
Sub.x = 30
20
Can anybody please tell me how this code run?
Why doesn't the costructor of class Base run?
Because you created a new Sub object instance. The class Sub has the printMessage() method overriden, which means that the Base.printMethod() is not being executed.
The constructor of the Base class runs, but the this.printMessage() executes the printMessage method from the Sub class.
Immediatelly after the Sub's constructor has been invoked, the Base constructor is being called. It prints Sub.x = 0 because no x (in Sub) has been set so far. After that the value x gets assigned.
After the Base constructor is done, the rest of the Sub constructor is being executed. It prints calls the Sub's printMessage method again, but this time the value x has a value, and it prints Sub.x = 30.
The 20 comes from the System.out.println(b.x);.
You might wonder, why the value xis not assigned during the first printMessage call? Because you have x in your Sub class as well, so the x from the Base class is not visible!
Your SuperClass constructor is always called but "Polymorphic behaviour cannot be seen when accessing overridden member variables".
Base b = new Sub();
System.out.println(b.x);
Now if you access x(which is present in both subclass and superclass) it is actually the type of reference variable which determines the value.
Note: This behaviour is different with overridden methods,in this case it is actually the type of object which determines the method to be called not the type of reference variable.
The constructor
public Sub() {
this.printMessage();
x = 40;
}
is equivalent to
public Sub() {
super();
this.printMessage();
x = 40;
}
So when you create
Base b = new Sub();
Base's constructor gets executed followed by Sub's constructor. See JLS 8.8.7, which states
The first statement of a constructor body may be an explicit
invocation of another constructor of the same class or of the direct
superclass
Base's constructor is calling printMessage() which is overriden by Sub. When it gets called from Base's constructor printMessage() prints x of Sub which is not yet initialized. This is an anti pattern, so Sub.x = 0 gets printed (x is not yet initialized, and hence default value of int which is 0 )
Now once the Base's constructor finishes, Sub's constructor gets called and now the x is initialized to 30 why?
because
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
....
essentially means
class Sub extends Base {
int x;
public Sub() {
{
x=30;
}
this.printMessage();
x = 40;
}
....
hence this time printMessage() prints Sub.x = 30
finally 20 is printed because fields are NOT overriden.
When ever we are creating child class object then the following sequence of events will be executed automatically.
Step 1.Identification of instance members from parent to child and initialize them to default value.
after first step
Base instance variable is int x=0;
Sub instance variable is int x=0;
Step 2. Execution of instance variable assignments and instance blocks only in parent class
after second step
Base class instance variable is int x= 10;
Sub class instance variable is int x = 0;
Step 3.Execution of parent class constructor.
after third step
here you have a "printMessage()" invocation.It is overridden in child class Sub
So Sub class method is executes and prints Sub class's variable x value,which is now assigned as 0 only.
So the out put now "Sub.x = 0".
and Base class int x = 20;
Sub class int x = 0;
Step 4.Execution of instance variables and instance blocks in child class.
After 4th step
Base class int x=20;
Sub class int x=30;
Step 5.Execution of child constructor.
After 5th step.
In Sub class constructor you have "printMessage()" method invocation.So it will executes and prints output.
So the out put now "Sub.x = 30".
After the method invocation you have an assignment.
So now Base class int x=20;
Sub class int x=40;
For now your Sub class constructor created successfully.
Now you a print statement of variable x on type reference "Base".So now "Base" class variable x will be prints as output.
So the out put is "20".
I have a few cases I wonder about. First, if you have no constructor:
class NoCons { int x; }
When I do new NoCons(), the default constructor gets called. What does it do exactly? Does it set x to 0, or does that happen elsewhere?
What if I have this situation:
class NoCons2 extends NoCons { int y; }
What happens when I call new NoCons2()? Does NoCons's default constructor get called, and then NoCons2's constructor? Do they each set the respective x and y fields to 0?
What about this version:
class Cons2 extends NoCons { int y; public Cons2() {} }
Now I have a constructor, but it doesn't call the super class's constructor. How does x ever get initialized? What if I had this situation:
class Cons { int x; public Cons() {} }
class NoCons2 extends Cons { int y; }
Will the Cons constructor be called?
I could just try all these examples, but I can't tell when a default constructor is run. What's a general way to think about this so that I'll know what happens in future situations?
When a Java class has no constructor explicitly defined a public no-args default constructor is added so:
class Cons { int x; }
is equivalent to:
class Cons { int x; public Cons() {} }
A subclass's constructor that doesn't explicitly define which of its parent's constructor it calls will automatically call the default constructor in the parent class before it does anything else. So assuming:
class A { public A() { System.out.println("A"); } }
then this:
class B extends A { public B() { System.out.println("B"); } }
is exactly equivalent to:
class B extends A { public B() { super(); System.out.println("B"); } }
and the output in both cases will be:
A
B
So when you do:
new NoCons2();
The order is:
NoCons's default constructor called, although this is technically the first part of (2); and then
NoCons2's default constructor called.
You want to refer to the Java Language Specification section 12.5 Creation of New Class Instances to get the official rules of object creation. The relevant section is:
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 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. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
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.
So in your examples, when no constructor is supplied in your class definition, the default one is inserted for you. When you write
new NoCons2();
First the super constructor is called (a call to super() is inserted for you because you don't make the call explicitly).
Instance variables for the class being constructed are initialized.
The rest of the constructor body is executed (nothing in your case).
In your first example, x will be set during the construction of NoCons and y will be set during the construction of NoCons2.
So the exact sequence of events in that example will be something like:
NoCons2 constructor called.
Call to super(), goto 3
NoCons constructor called.
Call to super(), which is an implicit call to Object().
Whatever happens in Object constructor.
x is set to 0.
finish body of NoCons constructor, return control back to NoCons2 constructor.
y is set to 0.
finish body of NoCons2 constructor
NoCons2 object construction complete.
cletus answered the biggest of the questions. The answer to the other is that member variables in Java are initialized to 0, null or false (depending on the type).
Here is essentially what happens when "new" is called:
the memory is allocated (enough to hold all of the data members of the class, and all of the parent classes, and some housekeeping information)
the allocated memory is set to zero (which means 0, 0.0, false, null depending in the type)
the constructor is called for the class that is after "new" is called.
more things happen (coming after the next part)
If you do not provide a constructor the compiler does the following:
creates a no-argument constructor
the created constructor has the same access as the class (so public or package)
super() is called.
So when the constructor of the class after the "new" is called the very first thing it does is call "super()" which calls the parent constructor. This happens all the way up to java.lang.Object.
Before the body of the constructor is run the VM does the following:
the instance variables that are assigned values are given them
then the instance initializer block, if present is run.
The following code shows all of this:
public class Main
{
private Main()
{
}
public static void main(final String[] args)
{
final Foo fooA;
final Foo fooB;
fooA = new Foo(7);
System.out.println("---------------------");
fooB = new Foo(42);
}
}
class Bar
{
protected int valueA = getValue("valueA", 1);
protected int valueB;
static
{
System.out.println("static block for Bar happens only one time");
}
{
System.out.println("instance block for Bar happens one time for each new Bar");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
}
Bar()
{
super(); // compiler adds this - you would not type it in
System.out.println("running Bar()");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
valueB = getValue("valueB", 2);
}
protected static int getValue(final String name, final int val)
{
System.out.println("setting " + name + " to " + val);
return (val);
}
}
class Foo
extends Bar
{
protected int valueC = getValue("valueC", 1);
protected int valueD;
static
{
System.out.println("static block for Foo happens only one time");
}
{
System.out.println("instance block for Foo happens one time for each new Foo");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
}
Foo(final int val)
{
super(); // compiler adds this - you would not type it in
System.out.println("running Foo(int)");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
valueD = getValue("valueD", val);
}
}
Consider this:
class A {
int x =5;
}
class B extends A{
int x =6;
}
public class CovariantTest {
public A getObject() {
return new A();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest {
public B getObject(){
return new B();
}
}
As far as I know, the JVM chooses a method based on the true type of its object. Here the true type is SubCovariantTest, which has defined an overriding method getObject.
The program prints 5, instead of 6. Why?
The method is indeed chosen by the runtime type of the object. What is not chosen by the runtime type is the integer field x. Two copies of x exist for the B object, one for A.x and one for B.x. You are statically choosing the field from A class, as the compile-time type of the object returned by getObject is A. This fact can be verified by adding a method to A and B:
class A {
public String print() {
return "A";
}
}
class B extends A {
public String print() {
return "B";
}
}
and changing the test expression to:
System.out.println(c1.getObject().print());
Unless I'm mistaken, methods are virtual in java by default, so you're overriding the method properly. Fields however (like 'x') are not virtual and can't be overriden. When you declare "int x" in B, you are actually creating a totally new variable.
Polymorphism doesn't go into effect for fields, so when you try and retrieve x on an object casted to type A, you will get 5, if the object is casted to type B, you will get 6.
When fields in super and subclasses have the same names it is referred to as "hiding". Besides the problems mentioned in the question and answer there are other aspects which may give rise to subtle problems:
From http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html
Within a class, a field that has the
same name as a field in the superclass
hides the superclass's field, even if
their types are different. Within the
subclass, the field in the superclass
cannot be referenced by its simple
name. Instead, the field must be
accessed through super, which is
covered in the next section. Generally
speaking, we don't recommend hiding
fields as it makes code difficult to
read.
Some compilers will warn against hiding variables