4

There is class T:

public class T
{
    protected String name;
    public T(String name)
    {
        this.name = name;
    }
    public String toString()
    {
        return "T:"+this.name;
    }
}

Class G:

public class G extends T
{
     public G(String name)
     {
          super(name);
     }
     public String toString()
     {
          return "G:" + super.toString();
     }
}

When I run

G a3 = new G("me");
System.out.println((T)a3)

It prints G:T:me.

I don't understand why. I thought it would print T:me. I claim this because it was casted as object T. And therefore, using the toString() of class T. However, I'm wrong. Why does this happen?

I know there are not good names for classes, it's a question about understanding polymorphism and inheritance, not just to write a specific code I need.

Pichi Wuana
  • 732
  • 2
  • 9
  • 35
  • What does `super.toString()` do? – Savior Apr 06 '16 at 15:47
  • Are you asking me a question for you to understand or a question so I can think about it? With that code it will activate the method toString() of the class T. – Pichi Wuana Apr 06 '16 at 15:49
  • So you would think about it. – Savior Apr 06 '16 at 15:50
  • @Pillar Oh so am I right? – Pichi Wuana Apr 06 '16 at 15:51
  • The part I don't understand is **why** it doesn't activate the method of toString() on the class T. – Pichi Wuana Apr 06 '16 at 15:52
  • Yes, which you also see from your current output. Your object is of dynamic type `a3`. The cast doesn't change that. When `println` eventually invokes `toString` on it, its `G`'s implementation that gets invoked, appending the `G`, then `super.toString()` gets invoked, calling `T`'s implementation, which returns `T:me` that gets appended to the `G`. – Savior Apr 06 '16 at 15:53
  • Because of dynamic dispatch, polymorphism, whatever you want to call it. – Savior Apr 06 '16 at 15:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/108422/discussion-between-pichi-wuana-and-pillar). – Pichi Wuana Apr 06 '16 at 15:55
  • @Pillar what is the difference between `System.out.println(a3);` and `System.out.println((T)a3);`? – Pichi Wuana Apr 06 '16 at 15:56
  • There is none. `println` expects `Object`. – Savior Apr 06 '16 at 15:56

3 Answers3

4

The method toString() in class G overrides the method in class T, so it gets chosen. The static type of the object is used by the compiler to decide which overload of a method to use. It could only make a difference if there were two different toString() methods defined on T to choose from, and / or G defined another toString() overload somehow - although it's not really possible when there are no arguments to the method.

sisyphus
  • 6,174
  • 1
  • 25
  • 35
3

The crucial point here is a cast does not change the object in any way. All it does is allow you to treat it as a different (compatible) type. The objects functionality stays exactly the same.

The code:

 public String toString()
 {
      return "G:" + super.toString();
 }

completely removes the old toString to a point where it is no longer accessable at all (mostly).

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • What do you mean treat it as a different compatible type? – Pichi Wuana Apr 06 '16 at 16:01
  • 1
    @PichiWuana - compatible means you can cast up or down but you cannot cast across. E.g. You **can** cast any object up to `(Object)` or down to it's actual type but not across to something like `Integer` or `HashMap`. – OldCurmudgeon Apr 06 '16 at 16:08
  • If `a4` is a **T** object, what would happen with `System.out.println((G)a4);`? – Pichi Wuana Apr 06 '16 at 16:20
  • @PichiWuana - It will **always** call the method of the actual object it has, not the type it is pretending to be. In your case if `a4` is a `T` then `System.out.println((G)a4)` will invoke `T.toString()` every time. – OldCurmudgeon Apr 06 '16 at 16:29
  • But can you cast it to T's *son*? – Pichi Wuana Apr 06 '16 at 16:40
3

G a3 = new G("me");

This line calls both the construcotrs of T as well as G.

public T(String name)
{
    this.name = name;
    // so, this.name gets initialised to me.
}

public G(String name)
 {
      super(name);
 }

Now, since you have overridden the toString() method, but, calling the System.out.println((T)a3) doesn't change the type of a3 from Object to any other type. It makes possible printing a3 as an object(since println() also accepts parameter of type Object), but, a3 is still being overridden in both the classes.

So, your toString() method will be called, thereby leading to printing of G:T:me..

Am_I_Helpful
  • 18,735
  • 7
  • 49
  • 73