Inner classes can seem tricky at first, but don't give up!
The outer class is AbstractTest. But as we'll see, this question is really about
anonymous inner classes -- not abstract classes.
So let's take a look... Inside AbstractTest, we have a method called getNum which is implemented to return the int 45. We also have a definition for an inner class called Bar. Inside Bar is a method called getNum, which is implemented to return the int 38.
Here's the trick: In main, it
looks like we're creating a new AbstractTest object. But actually, we're creating an object based on an anonymous inner class and upcasting that object to AbstractTest.
When you create an anonymous inner class, you essentially call the constructor of an existing class --
but after the constructor's arguments (where you would normally have just a semicolon), you insert a new class definition in brackets. From this, you get is an object that is automatically a subclass of the class whose constructor you called,
and that object is automatically upcast from the anonymous type to the class whose constructor you called.
In this case, we have an object that extends AbstractTest, and is automatically upcast to AbstractTest. But in the anonymous class definition -- the part in brackets slipped in between "new AbstractTest()" and the semicolon -- AbstractTest's getNum method is overridden to return 22 rather than 45.
Next, we do it again: It
looks like we're creating an instance of the inner class Bar; but actually, we're creating an object with another anonymous class and upcasting that object to AbstractClass.Bar. In this anonymous class definition (the brackets inserted after the constructor call), Bar's getNum method is overridden to return 57 rather than 38.
So now, when we call f.getNum(),
polymorphism kicks in. The method invoked is the one associated with the actual runtime type (the anonymous class) rather than the declared type (AbstractTest.Bar). In other words, the overridden version of the method is invoked, so f.getNum() returns 57.
The same thing happens when we call t.getNum(). The overridden version is invoked, and t.getNum() returns 22.
Note the comment lines in the code below.