Java 列表对象的继承和转换

Java 列表对象的继承和转换,java,list,inheritance,casting,downcast,Java,List,Inheritance,Casting,Downcast,我无法将水果列表向下转换为列表中包含的水果子类 public class Response { private List<Fruit> mFruitList; public List<Fruit> getFruitList() { return mFruitList; } } public class Fruit { } public class Orange extends Fruit { } List<Fruit&

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

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();
公共类响应{
私人名单;
公共列表getFruitList(){
返回mFruitList;
}
} 
公共级水果{
}
公共级橙汁{
}
List oranges=response.getFruitList();

我如何投射橙色,使其成为橙色类的列表?这是一种糟糕的设计模式吗?基本上,我从一个服务器得到一个JSON响应,它是一个水果列表。对于每个对Web服务的特定调用,我知道我将得到哪个Fruit子类,因此我需要适当地转换该列表

您应该强制转换列表,并测试每个元素是否为橙色的实例,然后在测试后强制转换为橙色。这是“最佳实践”。

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

如果您完全确定该列表将仅为
Orange
实例,并且它使您的代码更易于向下转换,那么就使用它

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

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

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

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();
公共类响应{
私人名单;
公共列表getFruitList(){
返回mFruitList;
}
} 
响应=//创建
List oranges=response.getFruitList();

编辑:我说的模板是泛型类型。对不起,我现在有太多C++了,

> P。由于这种继承和铸造将不会以您期望的方式工作。在您给出的示例中,您可以将桔子和苹果都放在

列表中。如果列表中既有苹果又有橙子,您如何将其转换为
列表

如果您需要一个
列表
,那么为什么还要麻烦使用
列表
。如果您明确地强制转换它,并且您确切地知道它包含什么,那么它可能是一个不必要的抽象

如果您正在使用一个API,您无法更改它,但您确切知道它包含什么,那么您应该使用instanceof check循环,以确保在需要使用
橙色
API时,明确地将每个
水果
实例转换为
橙色

List<Fruit> getFruits() {...}
List getFruits(){…}
你不能打字

List<Orange> oranges = (List<Orange>) getFruits();
List橙子=(List)getFruits();
由于类型擦除,在运行时getFruits的类型只是List。编译器甚至不允许您进行向下转换(我对此表示怀疑,所以在回答之前我在Eclipse中进行了尝试)

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

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

List您是否尝试过只
List oranges=(List)response.getFruitList()?是的,我尝试了很多强制铸造,但没有积极的结果。我正在考虑我的方法。也许最好将Response子类化,并为每个水果子类实现适当的列表。90%的响应包含每个水果类相同的成员,除了列表。更新,共识是-泛型而不是子类。你所说的模板到底是什么意思?我的理解是java没有C++所说的模板,这很有趣。让我试试这个。也许最好将Response子类化,并为每个相应的水果子类实现适当的列表?@Arch Stanton,而不是将
Response子类化,您还可以对其进行泛型化<代码>公共类响应{private List fruit;/*etc.*/}
@talnicolas ha…我还没有看到你的评论。英雄所见略同同意。我最后一次使用Java是在泛型被引入之前,我开始对它们感到困惑。
@SuppressWarnings("unchecked")
List<Orange> oranges = (List<Orange>) getFruits();
@SuppressWarnings("unchecked")    
List<Orange> oranges = (List) getFruits();
List<Orange> oranges = Arrays.asList((Orange[])getFruits().toArray())