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”的方法?
我知道在我的脑海中存在一些关于多态性概念的误解。请帮我澄清一下这个误会!
答案 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
方法。