Reputation: 199
class ClassA {
String whoAmI() {
return "ClassA";
}
}
class ClassB extends ClassA{
String whoAmI() {
return "ClassB";
}
}
class Main {
public static void main(String[] args) {
ClassA obj1 = new ClassA();
ClassA obj2 = new ClassB();
System.out.println(obj1.whoAmI());
System.out.println(obj2.whoAmI());
}
}
Output of the code above is:
ClassA
ClassB
In the code above output is as expected that I can see the methods of class "ClassB" when I am creating a reference variable of class "ClassA" and instantiating with "new ClassB();", but why it is not same in case when I creating the reference variable of interface "List" and instantiating it by using its implementing class "ArrayList" (I know that we can't create objects of interfaces directly)?
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List objList = new ArrayList();
objList.add("One");
objList.add("Two");
objList.add("Three");
System.out.println(objList.get(1)); // Only able to call methods of interface "List", but not methods of its implementing class "ArrayList. WHY?"
}
}
If class "ArrayList" is implementing interface "List" then why I am not able to call methods of class "ArrayList"?
I know that there is some misunderstanding in my mind about the concept of Polymorphism. Please help me to clear that misunderstanding!
Upvotes: 1
Views: 156
Reputation: 1588
polymorphism has two concepts about methods.
method overloading - where you overload/add/has different parameters in your method
ex:
class ClassA {
String whoAmI() {
return "ClassA";
}
}
class ClassB extends ClassA{
// you are overloading the method whoAmI from class A
String whoAmI(String name) {
return "ClassB "+name;
}
}
method overriding - where you override/change the default function of a method
class ClassA {
String whoAmI() {
return "ClassA";
}
}
class ClassB extends ClassA{
// override whoAmI method change function
String whoAmI() {
//do something
int foo = 5 + 10;
return "ClassB foo: "+foo;
}
}
and in your question
class ClassA {
String whoAmI() {
return "ClassA";
}
}
class Main {
public static void main(String[] args) {
Object obj1 = new ClassA();
obj1.whoAmI();
}
}
from your code snippet above you are referencing an object ClassA()
to an Object
WHICH the object does'nt have the whoAmI()
method. you're saying that the obj1
is a ClassA() type of object which they have different sets of methods.
Object
/
ClassA()
|
method:whoAmI()
referring to the class hierarchy above. the classA()
has a method of whoAmI()
and the Object
has equals(), hashCode(), getClass(), etc...()
when you're extending to an Object
the super class
doesn't inherit the methods inside the child class
. In your example since ClassA()
is extending Object
(super class), Object
will not inherit the whoAmI()
method but it is the other way around. the ClassA()
will inherit the methods inside Object
. and if you are referencing your ClassA()
to Object
and accessing a method inside ClassA()
you need to cast your Object
to ClassA()
to tell the compiler that i am calling a method from ClassA()
.
EDITED:
in your example the output is not the same because you are giving a reference of ClassB()
to ClassA()
that overrides the method whoAmI();
and in your List
example, ArrayList
implements List
but the instance variable is A List
. refer to "diagram below"
Custom class
Class A Class B extends A
method: whoAmI() method override: whoAmI()
output: "i am class A" output: "i am new class B"
method: fooMethod()
output: "my own method"
so when you declare a Class A
object you will be using the class a methods,fields etc
ClassA obj = new ClassA();
once you change the reference object to ClassB()
you will be now using the ClassB's
overriden method/different sets of fields, etc.. but it doesnt mean that you can call fooMethod()
easily because remember it is still a ClassA
the methods in ClassB
inside ClassA
will be overriden.
ClassA obj = new ClassB();
// override whoAmI() method changed output
but when you cast the obj to ClassB()
it is like you are telling the compiler that this obj is a ClassB()
this is when you can use the fooMethod()
because the compiler thinks that obj(casted)
is a ClassB
((ClassB)obj).fooMethod();
i tried the best way i can to explain this the simplest way i know. cheerioo
Upvotes: 2
Reputation: 279880
Let's say you had this
Object ref;
if (new Random().nextInt(2) % 2 == 0)
ref = new ClassA();
else
ref = new String("whatever");
Should you be able to invoke a whoAmI
method on the object referenced by the variable ref
? No. The compiler cannot consistently know what type of objects your program's variables will hold at runtime. As such, methods are resolved at compile time based on the type of the variables. The Object
type does not have a whoAmI
method.
Upvotes: 0
Reputation: 823
Object obj1 = new ClassA();
In this line, Object
is considered the static type of the variable, and ClassA
is considered the dynamic type of the variable.
Static types are always used to guarantee the existence of a field or method by the compiler, while dynamic types are what's actually used to call methods when the program runs.
The idea is this: since the static type must always be a superclass of the dynamic type, the static type is used to guarantee that no matter what subclasses you use as the dynamic type of the variable, they will always at least support the methods of the superclass. For example, every Object has a hashCode() method and a toString() method, because these methods are considered essential to all objects in Java. You would always be allowed to call obj1.hashCode()
.
Because the Object class does not contain a whoAmI()
method, however, the compiler will throw an error.
Upvotes: 0