5

我无法将水果列表转换为列表中包含的水果子类。

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 的哪个子类,因此我需要适当地转换该 List。

4

5 回答 5

7

如果您知道每个特定调用将获得 Fruit 的哪个子类,那么您应该使用泛型而不是强制转换列表。

public class Response<T extends Fruit> {
    private List<T> mFruitList;
    public List<T> getFruitList() {
        return mFruitList;
    }
} 

Response<Orange> response = // create
List<Orange> oranges = response.getFruitList();

编辑:模板是指泛型类型。抱歉,我现在的 C++ 太多了

于 2011-06-15T16:41:00.600 回答
3

类型转换背后的整个想法是能够告诉编译器,“嘿,我比你知道的更多。” 在您的代码中,编译器无法安全地向下转换为List<Fruit>List<Orange>因为它无法知道列表在运行时将包含什么。

如果您绝对确定该列表将只是Orange实例,并且它使您的代码更易于管理,那就去吧。

List<Orange> oranges = (List<Orange>) response.getFruitList();

当然,编译器会给你一个警告,因为你正在做一些它认为你不应该做的事情。CastClassException并且只知道如果你错了,JVM 可能会通过抛出 a 笑到最后!

于 2011-06-15T16:37:54.177 回答
1

将泛型视为列表可以包含哪些类型的对象的大门。由于这种继承和强制转换不会以您期望的方式工作。在您提供的示例中,您可以将 Oranges 和 Apples 放在您的List<Fruit>. 如果列表同时包含苹果和橙子,您如何将其转换为List<Orange>.

如果您需要一个,List<Orange>那么为什么还要打扰List<Fruit>. 如果您无论如何都明确地转换它并且您确切地知道它包含什么,那么它可能是一个不必要的抽象。

如果您正在使用一个无法更改但您确切知道它包含什么的 API,那么您应该使用 instanceof 检查进行循环,以确保并明确地将每个Fruit实例强制转换为Orange您需要OrangeAPI 的时间。

于 2011-06-15T16:54:49.460 回答
0

您应该投射 List,并测试每个元素是否为instanceof Orange,然后在 Oranges 中进行测试。这是“最佳实践”。

于 2011-06-15T16:34:51.540 回答
0

给定

List<Fruit> getFruits() {...}

你不能打字

List<Orange> oranges = (List<Orange>) getFruits();

由于类型擦除,在运行时 getFruits 的类型只是 List。编译器甚至不会让你做向下转换(我有疑问,所以我在回答之前在 Eclipse 中尝试过)。

您可以告诉编译器您的列表将包含 Fruit 的某个子类,在这种情况下,您需要在方法上使用通配符:

List<? extends Fruit> getFruits() {...}

然后强制转换成为可能,但带有类型安全警告:

@SuppressWarnings("unchecked")
List<Orange> oranges = (List<Orange>) getFruits();

鉴于 getFruits 的运行时类型List,您可以丢弃泛型类型信息并使用不安全的分配:

@SuppressWarnings("unchecked")    
List<Orange> oranges = (List) getFruits();

也许一种更优雅的方式,因为它清楚地表明了你的意图,尽管需要更多的系统资源:

List<Orange> oranges = Arrays.asList((Orange[])getFruits().toArray())

Java 中的数组在运行时会保留其类型信息,因此从编译器的角度来看,强制转换是有效且“安全的”,但如果您在水果篮中传递一些苹果,它可能会引发运行时异常。

于 2011-06-15T17:15:47.213 回答