简体   繁体   中英

Java Polymorphism: Please Help Me to Understand Polymorphism

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!

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM