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 Animal
s, 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 methodsm
(both static and instance) of the superclass for which all of the following are true:
m
is a member of the direct superclass ofC
.m
ispublic
,protected
, or declared with package access in the same package asC
.- No method declared in
C
has a signature that is a subsignature of the signature ofm
.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 fromT
a method declared in a supertype ofT
, or is not override-equivalent to a public method ofObject
, 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 invocationsuper();
, 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:
- Look at the object that the method is called on (
a
) and get its declared type. This type isA
. - In class
A
and all of its super types, make a list of all methods that are namedshow
. The compiler will find onlyshow(A)
. It does not look at any methods inB
orC
. - From the list of found methods, choose the one that best matches the parameter (
b
) if any.show(A)
will acceptb
, 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.
- Get the object on which the method is called (which is already on the stack by then), which is
a
. - Look at the actual runtime type of this object. Since
a = new B()
, this type isB
. - Look in
B
and try to find the methodshow(A)
. This method is found sinceB
overrides it. If this had not been the case, it would look in the super classes (A
andObject
) until such a method is found. It is important to note that it only considersshow(A)
methods, so eg.show(B)
fromB
is never considered. - The runtime will now call method
show(A)
fromB
, giving theString
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
Draw a Circle with a Radius and Points Around the Edge
How to Run Testng from Command Line
Java:Cannot Format Given Object as a Date
Do JSON Keys Need to Be Unique
How to Configure Maven for Offline Development
Converting Long to Date in Java Returns 1970
Java Error: Only a Type Can Be Imported. Xyz Resolves to a Package
Passing Values Between Jframes
How to Represent Double Values as Circles in a 2D Matrix in Java
Post Request Send JSON Data Java Httpurlconnection
Whitespace Matching Regex - Java
Are Static Variables Shared Between Threads
Most Efficient Way to Increment a Map Value in Java
What Is Simplest Way to Read a File into String