What code placed after the comment //Here will result in calling the getFields method resulting in the output of the string "Agg"? 1) System.out.println(a.getFields()); 2) System.out.println(a.name); 3) System.out.println((Base) a.getFields()); 4) System.out.println( ((Agg) a).getFields()); Had there been a getFields() in class Base, I knew that the method would be invoked based on the object and not the reference type Base. I thought this was the rule which applied always to all instance,non-final methods, irrespective of whether they are overridden or not. the method would be invoked based on the object . Going by this, I selected options 1 and 4, expecting this to give the same results whether I had a getFields() defined in class Base or not. Well, I got it wrong . Marcus explains that the correct answer is 4. The explanation -The Base type reference to the instance of the class Agg needs to be cast from Base to Agg to get access to its methods. The method invoked depends on the object itself, not on the declared type. So, a.getField() invokes getField() in the Base class, which displays Base. But the call to ((Agg)a).getField() will invoke the getField() in the Agg class. You will be unlucky to get a question as complex as this on the exam. I have compiled and verified that Marcus's answer is correct. But I don't understand it. The object created is Agg, so why does a.getFields invoke a.getField in the Base class ? I have seen several answers in this forum where it is asserted that method invocation depends on the object, none of them seemed to mention that this is conditional(ie works only when overriding is in force). Would really appreciate if someone could give an accurate explanation of how method invocation works with objects and references. I did look at the JLS but this particular section is not very clear to me. thanks a ton! cheers Sajida
First off, this is a common question that you'd fine on the exam, so I suggest you study it. Okay, you know that you can upcast without a problem in a hierarchy. This is because all the descendants can see who have come before them. So if you have a class shape, and from that comes a polygon, and from that comes a triangle. The triangle inherits from the polygon and the shape. But it is impossible for shape to know who comes after them. So, while a triangle is indeed a shape, and saying Shape s= new Triangle() is perfectly legal, if you called a method with s, s has no idea what the methods of class Triangle are since Triangle has come after shape. So you have to use a cast to get rid of this ambiguity. I hope that helps, I know I havent' explained it as well as I could, but I think you can get the picture.
Hi Sean, Thanks for your reply. if you called a method with s, s has no idea what the methods of class Triangle are since Triangle has come after shape That is exactly how overriding works ! When I say s.shape, the shape method of Triangle is invoked(provided of course that there is such a method in Triangle. If there is no such method, then shape has to be cast to Triangle, I get that from your explanation. What I needed a clarification was on the statement 'that the object type determines which method is going to be invoked'. This is something which Marcus has also mentioned in the explanation. It evidently does not seem to hold true in all cases. Is this understanding correct ? Thanks! Sajida
Hi sajida, I'm not sure I can explain this properly but I'll take a shot at it. When creating a new instance, the compiler knows two things: the declared type of the object, in this case <code>Base</code> and the type of the <code>new</code> expression, in this case <code>Agg</code>, which will be the runtime type. It checks to make sure the runtime type is assignable to the declared type. That is all it is concerned with. When it hits the statement <code>System.out.println(a.getFields())</code> it is not smart enough to know that 'a' will have a runtime type of 'Agg'. It is only aware of the declared type 'Base'. As 'Base' does not have a <code>getFields</code> method, an error occurs. The key is that the compiler only knows the declared type. If the declared type contains methods that also appear in the runtime type, you don't have to worry about casting. It won't matter if the runtime type is different since the method will be available to any legal 'Base' object via inheritance. Hope that helps. ------------------ Jane Griscti Sun Certified Programmer for the Java� 2 Platform
Jane, your explanation was perfect and it fit the missing gaps in my analysis I needed to see that the problem was how the compiler performs its checks. Its absolutely logical. So the compiler does the same check even when there is overriding and it is satisfied as long as there is a method matching that declared type. Which method is invoked at runtime is an entirely different matter. I needed to get that distinction between compilation and runtime checks. Great! Thank Jane and Sean for your answers ! Regards, Sajida