Why Java Polymorphism Not Work in My Example

why java polymorphism not work in my example

This is one of the problems of using visible fields - you end up using them...

You've got a color field in both Rect and CRect. Fields are not polymorphic, so when you use cr2.color, that uses the field declared in Rect, which is always set to "transparent".

Your CRect class should not have its own color field - it should supply the colour to the superclass constructor. It makes no sense for a single rectangle to have two different color fields - it could have borderColor and fillColor, of course - but just color is too ambiguous...

Why polymorphism doesn't play a role?

Polymorphism exists for methods, not for fields. Therefore getAge(), which is only implemented in the Animal class, returns the member of the Animal class.

If you override getAge() in the Wolf class, i.e. add a

@Override
public int getAge() {
return age;
}

you'll get the value of the Wolf class member.

That said, it doesn't make sense to have an age member in both the base class and sub-class. If it's a property common to all Animals, it should only be in the Animal class.

So your Wolf class will become :

public class Wolf extends Animal {
Wolf(int age) {
super(age);
}
}

And your Animal constructor doesn't make sense. You should assign the passed age argument to the member of the class :

public Animal(int age) {
this.age = age;
}

java polymorphism and inheritance problems

My first solution (as I suggested in comments) would be to move myFunction from the EmployeeFacade to Employee, EmployeeImpl and other subclasses and thus use virtual methods directly. If this for some reasons is not an option, my next solution would be introducing virtual "proxy" function to Employee and using it to dispatch call properly:

public class MainApp {
public static void main(String[] args){
Employee emp = new EmployeeImpl();
emp.callMyFunction();
}
}

abstract class Employee
{
public void callMyFunction()
{
//here is huge amount of code, which all child class has the same
//excepted this line is called to a different function by it instant types.
callMyFunctionImpl();
}

protected void callMyFunctionImpl()
{
EmployeeFacade.myFunction(this);
}
}

class EmployeeImpl extends Employee
{
@Override
protected void callMyFunctionImpl()
{
EmployeeFacade.myFunction(this);
}
}

class EmployeeFacade
{
public static void myFunction(Employee emp)
{
//same data to database
System.out.println("Employee: " + emp.getClass().getName());
}

public static void myFunction(EmployeeImpl emp)
{
//same data to database
System.out.println("EmployeeImpl: " + emp.getClass().getName());
}
}

Polymorphism doesn't work in method arguments in Java

The problem here is that Java does not support dynamic binding of method arguments. What you see is static binding, i.e. the overload of the method to call is chosen at compile time.

See also: Static Binding and Dynamic Binding

Why doesn't Java allow me to perform this type of polymorphism/inheritance?

The compiler can't guarantee that there is an appropriate method at runtime.

You have a method that takes a Cat and you have a method that takes a Dog. You are trying to pass an Animal variable that references a Dog. What if would reference an Elephant? Then there would be no suitable method at runtime. That's why it won't let you compile.

Animal animal = new Elephant();
new RunActions().runAction(animal); // real problem now!

Can't seem to understand complex polymorphism

Explanation

public class AA {

private void foo() { ... }
^^^^^^^

}

Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:

A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:

  • m is a member of the direct superclass of C.
  • m is public, protected, or declared with package access in the same package as C.
  • No method declared in C has a signature that is a subsignature of the signature of m.

Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding

Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.

But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.


It's a bit tricky, so I would recommend you put the @Override annotation everywhere it's supposed to be.

public class BB extends AA {

@Override // it doesn't compile - no overriding here
public void foo() { ... }
@Override // it does override
public void goo() { ... }

}

It also might be helpful to detect another problem:

Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.

If a method declaration in type T is annotated with @Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.

Java Language Specification - 9.6.4.4. @Override

Illustration

If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.

Java Language Specification - 8.8.7. Constructor Body

To put it simply,

public BB() {
foo();
}

turns into

public BB() {
super();
foo();
}

Keeping super(); in mind, we can make the next illustration:

new BB()
AA() // super(); -> AA constructor
A#foo() // private method call
B#goo() // polymorphic method call
BB() // BB constructor
B#foo() // plain method call

How does polymorphism in Java work for this general case (method with parameter)?

In order to get why you get the result B and A twice, you need to know that there are 2 parts to this: compilation and runtime.

Compilation

When encountering the statement a.show(b), the compiler takes these basic steps:

  1. Look at the object that the method is called on (a) and get its declared type. This type is A.
  2. In class A and all of its super types, make a list of all methods that are named show. The compiler will find only show(A). It does not look at any methods in B or C.
  3. From the list of found methods, choose the one that best matches the parameter (b) if any. show(A) will accept b, so this method is chosen.

The same thing will happen for the second call where you pass c. The first two steps are the same, and the third step will again find show(A) since there is only one, and it also matches the parameter c. So, for both of your calls, the rest of the process is the same.

Once the compiler has figured out what method it needs, it will create a byte-code instruction invokevirtual, and put the resolved method show(A) as the one it should call (as shown in Eclipse by opening the .class):

invokevirtual org.example.A.show(org.example.A) : java.lang.String [35]

Runtime

The runtime, when it eventually gets to the invokevirtual needs to do a few steps also.

  1. Get the object on which the method is called (which is already on the stack by then), which is a.
  2. Look at the actual runtime type of this object. Since a = new B(), this type is B.
  3. Look in B and try to find the method show(A). This method is found since B overrides it. If this had not been the case, it would look in the super classes (A and Object) until such a method is found. It is important to note that it only considers show(A) methods, so eg. show(B) from B is never considered.
  4. The runtime will now call method show(A) from B, giving the String B and A as result.

More detail about this is given in the spec for invokevirtual:

If the resolved method is not signature polymorphic (§2.9), then the invokevirtual instruction proceeds as follows.

Let C be the class of objectref. The actual method to be invoked is selected by the following lookup procedure:

If C contains a declaration for an instance method m that overrides (§5.4.5) the resolved method, then m is the method to be invoked, and the lookup procedure terminates.

Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C; the method to be invoked is the result of the recursive invocation of this lookup procedure.

Otherwise, an AbstractMethodError is raised.

For your example, the objectref is a, its class is B and the resolved method is the one from the invokevirtual (show(A) from A)


tl:dr - Compile-time determines what method to call, runtime determines where to call it from.



Related Topics



Leave a reply



Submit