Java多态性:请帮助我理解多态性

时间:2014-11-28 06:49:50

标签: java inheritance 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());
    }
}

上述代码的输出是:

ClassA
ClassB

在上面的代码中输出正如预期的那样,当我创建类“ClassA”的引用变量并使用“new ClassB();”实例化时,我可以看到类“ClassB”的方法,但为什么它不是同样在我创建接口“List”的引用变量并使用其实现类“ArrayList”实例化它时(我知道我们不能直接创建接口对象)?

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?"
    }

}

如果类“ArrayList”正在实现接口“List”那么为什么我无法调用类“ArrayList”的方法?

我知道在我的脑海中存在一些关于多态性概念的误解。请帮我澄清一下这个误会!

3 个答案:

答案 0 :(得分:2)

polymorphism有两个关于方法的概念。

方法重载 - 在方法

中重载/添加/具有不同参数的位置

例如:

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;
    }
}

方法覆盖 - 覆盖/更改方法的默认功能

的位置
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;
    }
}

并在你的问题中

class ClassA {

    String whoAmI() {
        return "ClassA";
    }
} 

class Main {

    public static void main(String[] args) {

        Object obj1 = new ClassA();
        obj1.whoAmI(); 
    }   
}

从上面的代码段中,您将对象ClassA()引用到Object,该对象具有whoAmI()方法。您是说obj1是ClassA()类型的对象,它们有不同的方法集。

        Object
       /
   ClassA()
       |
    method:whoAmI()

指的是上面的类层次结构。 classA()的方法为whoAmI()Object的{​​{1}}方法equals(), hashCode(), getClass(), etc...() Object super class 39; t继承child class内的方法。在您的示例中ClassA()正在扩展Object(超类),Object将不会继承whoAmI()方法,但它是相反的方式。 ClassA()将继承Object内的方法。如果您引用ClassA()Object并访问ClassA()内的方法,则需要将Object强制转换为ClassA()以告诉编译器我是从ClassA()调用方法。

编辑:

在您的示例中输出不相同,因为您提供的ClassB()引用ClassA()会覆盖方法whoAmI();

List示例中,ArrayList实现了List,但实例变量为A List。请参阅下面的""

自定义类

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"

因此,当您声明一个Class A对象时,您将使用该方法,字段等

ClassA obj = new ClassA();

将参考对象更改为ClassB()后,您现在将使用ClassB's覆盖方法/不同的字段集等等。但这并不意味着您可以调用fooMethod()很容易因为记住它仍然是ClassA ClassB ClassA内的方法将被覆盖。

ClassA obj = new ClassB();
// override whoAmI() method changed output

但是当你将obj强制转换为ClassB()时,就好像你告诉编译器这个obj是ClassB()这是你何时可以使用fooMethod(),因为编译器认为obj(casted)ClassB

((ClassB)obj).fooMethod();

我尝试了最好的方式来解释这个我知道的最简单的方法。 cheerioo

答案 1 :(得分:0)

Object obj1 = new ClassA();

在此行中,Object被视为变量的静态类型,ClassA被视为变量的动态类型。

静态类型总是用于保证编译器对字段或方法的存在,而动态类型是实际用于调用方法的方法程序运行。

这个想法是这样的:因为静态类型必须始终是动态类型的超类,所以静态类型用于保证无论您使用什么子类作为变量的动态类型,他们总是在至少支持超类的方法。例如,每个Object都有一个hashCode()方法和一个toString()方法,因为这些方法对于Java中的所有对象都是必不可少的。您将始终可以拨打obj1.hashCode()

但是,因为Object类不包含whoAmI()方法,所以编译器会抛出错误。

答案 2 :(得分:0)

假设你有这个

Object ref;
if (new Random().nextInt(2) % 2 == 0)
    ref = new ClassA();
else
    ref = new String("whatever");

您是否可以在变量whoAmI引用的对象上调用ref方法?不可以。编译器无法始终知道程序变量在运行时将保留的对象类型。因此,根据变量的类型在编译时解决方法。 Object类型没有whoAmI方法。