列表对象的继承和转换
我在将水果列表转换为列表中包含的水果子类时遇到问题。
public class Response {
private List<Fruit> mFruitList;
public List<Fruit> getFruitList() {
return mFruitList;
}
}
public class Fruit {
}
public class Orange extends Fruit {
}
List<Fruit> oranges = response.getFruitList();
我如何投射橙子,使其成为橙类列表?这是一个糟糕的设计模式吗?基本上我从服务器收到一个 JSON 响应,它是一个水果列表。对于对 Web 服务的每个特定调用,我知道我将获得 Fruit 的哪个子类,因此我需要适当地转换该列表。
I'm having trouble casting a List of Fruit down to the Fruit subclass contained in the List.
public class Response {
private List<Fruit> mFruitList;
public List<Fruit> getFruitList() {
return mFruitList;
}
}
public class Fruit {
}
public class Orange extends Fruit {
}
List<Fruit> oranges = response.getFruitList();
How do I cast oranges so that it is a List of class Orange? Is this a bad design pattern? Basically I am getting a JSON Response from a server that is a List of Fruit. For each specific call to the Web Service, I know what subclass of Fruit I will get and so I need to cast that List appropriately.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您知道每个特定调用将获得 Fruit 的子类,那么您应该使用泛型而不是转换列表。
编辑:我所说的模板是指泛型类型。抱歉,我现在 C++ 太多了
If you known for each specific call that what subclass of Fruit you will get then you should use generics instead of casting lists.
EDIT: By templates I meant generic types. Sorry, I had too much C++ nowadays
类型转换背后的整个想法是能够告诉编译器,“嘿,我比你更了解这一点。”在您的代码中,编译器无法安全地将
List
向下转换为List
,因为它无法知道该列表在运行时将包含什么内容。如果您绝对确定该列表将只是
Orange
实例,并且它使您的代码更易于向下转换,那么就这样做吧。当然,编译器会给你一个警告,因为你正在做一些它认为你不应该做的事情。并且要知道,如果您错了,JVM 可能会通过抛出
CastClassException
笑到最后!The whole idea behind typecasts is to be able to tell the compiler, "Hey, I know more about this than you do." In your code, the compiler cannot safely downcast the
List<Fruit>
toList<Orange>
because it can't know what the list will contain at runtime.If you're absolutely certain that the list will be only
Orange
instances, and it makes your code more manageable to downcast, go for it.The compiler will give you a warning, of course, since you're doing something it thinks you shouldn't do. And just know that the JVM may have the last laugh by throwing a
CastClassException
if you were wrong!将泛型想象成一个列表可以包含哪些类型的对象的门。因此,继承和转换不会按您期望的方式工作。在您提供的示例中,您可以将橙子和苹果都放入
中。如果列表中同时包含苹果和橙子,如何将其转换为List
。List
如果您需要
那么为什么还要费心List
呢。如果您无论如何都显式地转换它并且您确切地知道它包含什么,那么它可能是不必要的抽象。List
如果您正在使用无法更改的 API,但您确切知道它包含什么内容,那么您应该循环使用 instanceof 检查,以确保并将每个
Fruit
实例显式转换为Orange
当您需要Orange
API 时。Think of generics like a gate for what types of objects a list can contain. Because of this inheritance and casting won't work in the way you would expect. In the example you gave you could put both Oranges and Apples in your
. If the list has both apples and oranges how can you cast it to aList<Fruit>
.List<Orange>
If you need a
then why even bother with theList<Orange>
. If you are explicitly casting it anyway and you know exactly what it contains its probably a needless abstraction.List<Fruit>
If you are working with an API you can't change but you know exactly what it contains then you should loop through with an instanceof check just to make sure and explicity cast each
Fruit
instance toOrange
when you need to theOrange
API.您应该转换 List,并测试每个元素是否是 Orange 的实例,并在测试后转换为 Oranges。这是“最佳实践”。
You should cast List, and test if each elements are
instanceof Orange
, and after the test cast in Oranges. This is the "best pratice".由于
你无法进行类型转换,
由于类型擦除,在运行时 getFruits 的类型只是 List。编译器甚至不会让你做downcast(我很怀疑,所以我在回答之前在Eclipse中尝试过)。
您可以告诉编译器您的列表将包含 Fruit 的某些子类,在这种情况下,您需要在方法上使用通配符:
然后可以进行强制转换,但会出现类型安全警告:
鉴于 getFruits < 的运行时类型em>is 列表,您可以丢弃泛型类型信息并使用不安全的分配:
也许是一种更优雅的方式,因为它清楚地表明了您的意图,尽管需要更多的系统资源:
Java 中的数组保留其类型信息在运行时,所以强制转换从编译器的角度来看是有效且“安全”的,但是如果您传递水果篮中的一些苹果,它可能会引发运行时异常。
Given
You can't typecast
Due to type erasure, at runtime the type of getFruits is just List. The compiler will not even let you do the downcast (I was in doubt, so I tried in Eclipse before answering).
You could tell the compiler that your list will contain some subclass of Fruit, in that case, you need to use a wildcard on you method:
Then the cast becomes possible, but with a type safety warning:
Given that the runtime type of getFruits is List, you can just discard the generics type information and use an unsafe assigment:
Maybe a more elegant way as it clearly states your intention, although requiring more system resources would be:
Arrays in Java preserve their type information at runtime, so the cast is valid and "safe" from the compiler perspective, but it can throw a runtime exception if you pass some apples in the fruit basket.