简体   繁体   English

ArrayLists中具有多态的类型不匹配

[英]Type Mismatch with polymorphism in ArrayLists

Here is my code:- 这是我的代码:

ArrayList<animal> myanimals = new ArrayList<animal>();
dog adog = new dog();
myanimals.add(adog);
System.out.println("" + myanimals.get(0).getClass());
dog newdog = myanimals.get(0);

I have created an ArrayList of animals(superclass) as myanimals and stored a dog(subclass) as the first element. 我已创建了一个ArrayList 动物(超类)作为myanimals和存储在狗(子类)作为第一个元素。 Then myanimals.get(0) returns a dog type object. 然后myanimals.get(0)返回一个狗类型的对象。 When this dog type object is referred by a dog type reference in the statement dog newdog = myanimals.get(0) , it shows an error saying : 当在语句dog newdog = myanimals.get(0)的语句中通过狗类型引用引用该狗类型对象时,它显示一条错误消息:

Type mismatch, cannot convert from animal to dog. 类型不匹配,无法从动物转换为狗。

Why does this happen? 为什么会这样?

The method call myanimals.get(0) returns an object reference of type Animal . 调用myanimals.get(0)的方法将返回Animal类型的对象引用。 Try Typecasating that Animal as a dog like :- 尝试将Animaldog一样打字 :-

dog newdog = (dog)myanimals.get(0);

Edit 1 : You asked about the output of the following line 编辑1 :您询问了以下行的输出

System.out.println(myanimals.get(0).getClass());

This actually prints out dog . 这实际上打印出了dog Why ? 为什么呢 Let's get some perspective. 让我们来看看。

What do you think the following program should output: 您认为以下程序应输出什么:

animal a = new dog();
System.out.println(a.getClass());

This prints out dog as expected. 这将按预期打印出dog But this doesn't mean that we can do this:- 但这并不意味着我们可以这样做:

animal a = new dog();
dog d = a;

This would throw a Compile-Time error. 这将引发编译时错误。 The Same is the problem with your case. 您的情况也一样。 The ArrayList is said to contain animal . 据说ArrayList包含animal Therefore, it would return animal even though you added a dog to it. 因此,即使您添加了dog ,它也会返回animal

Java is a statically typed language. Java是一种静态类型的语言。 Ie Java compiler checks code for type mismatches based on source code. 即,Java编译器根据源代码检查代码是否存在类型不匹配。 And your source code says, that myanimals.get(0) is of type Animal. 并且您的源代码说, myanimals.get(0)的类型为Animal。

Inheritance is a "IS-A" relationship, ie Dog IS-A Animal and can be used as value for variables of type Animal. 继承是一种“ IS-A”关系,即Dog IS-A Animal,可以用作Animal类型变量的值。 But the reverse is not true: Animal not IS-A Dog, it just could be (which makes casting possible - more on that later). 但是事实并非如此:动物不是IS-A Dog,它可能是(这使得铸造成为可能-稍后再进行介绍)。 That's why you get type mismatch. 这就是为什么您输入类型不匹配的原因。

It is only in runtime, long after your source code had been compiled into bytecode (and generics types erased), that myanimals.get(0).getClass() appears to be Dog by coincidence. 只有在运行时,将源代码编译为字节码(并擦除泛型类型)很长时间之后, myanimals.get(0).getClass()myanimals.get(0).getClass()似乎是Dog。 Compiler couldn't know that before. 编译器以前不知道这一点。

This makes sense: it prevents runtime errors that could be caught by static analysis. 这是有道理的:它可以防止可能由静态分析捕获的运行时错误。

But it's you, the developer, who knows for sure, that myanimals.get(0).getClass() will be of type Dog at runtime, so you can take responsibility and apply casting as in Shashwat's answer. 但是可以肯定的是,您是开发人员, myanimals.get(0).getClass()在运行时的类型为Dog,因此您可以像Shashwat的回答中那样承担责任并进行强制转换。 Compiler still checks if such casting is possible at all, and if yes - it would believe your word. 编译器仍会检查是否完全可以进行此类转换,如果可以,它将相信您的想法。

Basically, the type of an ArrayList is animal and you could add any kind of animals in there, not just dogs but cats, mice and parrots. 基本上,ArrayList的类型是animal ,您可以在其中添加任何种类的动物,不仅是狗,还可以是猫,老鼠和鹦鹉。 While the underlying type is indeed dog in your case, you can't safely know this. 而底层的类型确实是dog ,你的情况,你不能安全地知道这一点。 Otherwise you'd run into runtime exceptions as in this scenario: 否则,您将遇到这种情况下的运行时异常:

ArrayList<Animal> myanimals = new ArrayList<Animal>();
Cat myCat = new Cat();
myanimals.add(myCat);
System.out.println("" + myanimals.get(0).getClass());
Dog newdog = myanimals.get(0); // <-- this would be runtime exception if Java compiler allowed this

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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