3

Why this code only return the name of class C. when i am using the this it should return the name of class of the Constructor from which i am using it.

class A{
     public A() {
         System.out.println(this.getClass().getName());
     }
}
class B extends A{
    public B() {
        System.out.println(this.getClass().getName());
    }
}
class C extends B{
     public C() {
         System.out.println(this.getClass().getName());
     }
}
class Main{
    public static void main(String[] args){
         new C();
    }
}
Harshit Gupta
  • 719
  • 1
  • 9
  • 26

3 Answers3

4

this.getClass().getName() returns the name of the runtime type of the this instance. If you create an instance of C (new C()), it would always return "packagename.C". It doesn't matter if you call it from the code of class C or from code in super-classes of C.

Eran
  • 387,369
  • 54
  • 702
  • 768
1

Some related points:

1) The compiler will automatically insert a call to the no argument super class constructor in any constructor which does not contain an explicit call to the superclass constructor. (I encourage you to choose explicit behaviour over implicit behaviour when writing code, but this is a disputed point of style). At any rate to the compiler your code will look like:

class A{
    public A() {
        System.out.println(this.getClass().getName());
    }
}

class B extends A{
    public B() {
        super();
        System.out.println(this.getClass().getName());
    }
}

class C extends B{
    public C() {
        super();
        System.out.println(this.getClass().getName());
    }
}

class Main{
    public static void main(String[] args){
        new C();
    }
}

This makes it clear that the System.out.println is called three separate times.

2) The use of this inside a constructor to call methods on can generally lead to quite strange behaviour. See for example: this. That is because the initialisation works like this:

1) The class C constructor is called. At this point memory is allocated for a class C object and the objects meta data, including its class, interfaces implemented are filled out inside the VM. All fields, including inherited fields are initialised to their default value.

2) The class B constructor is called. Inside the constructor this refers to an object of class C, but none of the fields initialised in the C constructor will have been initialised yet. This will immediately call the class A constructor.

3) The class A constructor runs. Fields set in this constructor are initialised. The constructor executes methods and initialisations and returns and the stack passes back to the B constructor.

4) The B constructor executes its methods and returns control to the C constructor.

5) The C constructor returns.

So now we understand what happens: this chain prints C three times. I suspect that what you want is to write:

    class A{
    public A() {
        System.out.println(A.class.getName());
    }
}

class B extends A{
    public B() {
        super();
        System.out.println(B.class.getName());
    }
}

class C extends B{
    public C() {
        super();
        System.out.println(C.class.getName());
    }
}

class Main{
    public static void main(String[] args){
        new C();
    }
}

which will print out A,B,C.

phil_20686
  • 4,000
  • 21
  • 38
  • 1
    *"Its poor style to skip the super() call in the constructor of a subclass"* This is luckily not true. Btw: http://stackoverflow.com/questions/2712971/do-you-put-a-super-call-a-the-beginning-of-your-constructors – Tom Jun 29 '15 at 13:07
  • Well, people can disagree on elements of style. I would argue strongly that you should always choose explicit behaviour over implicit behaviour. Like putting final in argument definitions, I think it helps junior programmers, and I encourage it. – phil_20686 Jun 29 '15 at 13:28
  • @phil_20686 I disagree with your point because it does not matter if i use super() or not In both cases the output will be same – Harshit Gupta Jun 30 '15 at 05:04
  • Here are a list of other things which do not affect the output of a program: 1) Unit tests 2) Documentation and 3) Using @Override. Hopefully you do all of those things.... So clearly whether an action affects the output is not a very sensible criteria for whether its a good idea. Its just an argument about readability. – phil_20686 Jul 01 '15 at 10:27
0

First of all, when calling new Child(), since there is not a declared non-argument constructor in Child class, it will simple call super() which is invoking the Parent constructor.

Then, when executing this.getClass().getName(), here this stands for a Child instance, this is why you get "Child" as the result. Remember, Object#getClass() returns the most specific class the object belongs to. see more from here.

Harshit Gupta
  • 719
  • 1
  • 9
  • 26