Answers:
您始终可以通过将对象首先上载到Object来将其转换为任何类型。在您的情况下:
(List<Customer>)(Object)list;
您必须确保在运行时该列表仅包含Customer对象。
批评家说,这种强制转换表明您的代码有问题;您应该能够调整类型声明以避免这种情况。但是Java泛型太复杂了,也不是完美的。有时,即使您非常了解运行时类型,并且知道您尝试执行的操作是安全的,但有时您只是不知道是否有满足该编译器的漂亮解决方案。在这种情况下,只需根据需要进行粗铸,即可将工作留在家中。
@SuppressWarnings("unchecked")
。请注意,您也可以将(List)
改为而不是(Object)
。
这是因为尽管客户是对象,但客户列表不是对象列表。如果是这样,则可以将任何对象放入“客户”列表中。
.Cast<T>()
,一种叫做.OfType<T>()
。前者对每个元素执行强制转换(引发所需的异常),而后者过滤掉无法强制转换的元素(因此您将根据使用情况选择一个)。
instanceof
客户,会发生什么?
使用Java 8 Streams:
有时使用蛮力铸造就可以了:
List<MyClass> mythings = (List<MyClass>) (Object) objects
但是,这里有一个更加通用的解决方案:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
有很多好处,但是一个好处是,如果您不确定列表中包含的内容,则可以更优雅地投射列表:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
为我工作。
请注意,我不是Java程序员,但是在.NET和C#中,此功能称为逆方差或协方差。我还没有深入研究这些东西,因为它们是.NET 4.0中的新功能,因为它只是beta,所以我没有使用它,所以我不知道这两个术语中的哪个描述了您的问题,但让我描述与此相关的技术问题。
假设您被允许演员。注意,我说的是cast,因为这就是您所说的,但是可能有两种操作,即cast和conversion。
转换将意味着您将获得一个新的列表对象,但您说的是强制转换,这意味着您要将一个对象临时视为另一种类型。
这就是问题所在。
如果允许以下操作会发生什么(请注意,我假设在强制转换之前,对象列表实际上仅包含Customer对象,否则,即使在此虚拟版本的Java中,强制转换也不起作用):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
在这种情况下,这将尝试将不是客户的对象视为客户,并且您可能会在某一时刻收到运行时错误,无论是列表内的形式还是分配中的错误。
但是,泛型应该为您提供类型安全的数据类型(例如集合),并且由于它们喜欢在“保证”一词周围加注,因此不允许这种类型的转换以及随之而来的问题。
在.NET 4.0中(我知道,您的问题是关于Java的),这在某些非常特殊的情况下是允许的,在这种情况下,编译器可以保证您所做的操作是安全的,但是从一般意义上讲,这种类型的强制转换不会被)允许。对于Java来说也是如此,尽管我不确定是否有计划向Java语言引入协变和逆变。
希望比我有更好的Java知识的人可以告诉您有关Java将来或实现的细节。
正如其他人指出的那样,您不能保存它们的类型,因为a List<Object>
不是a List<Customer>
。您可以做的是在列表上定义一个进行就地类型检查的视图。使用Google收藏夹可以:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
根据您要对列表执行的操作,甚至可能不需要将其强制转换为List<Customer>
。如果只想将Customer
对象添加到列表中,则可以如下声明:
...
List<Object> list = getList();
return (List<? super Customer>) list;
这是合法的(嗯,不仅合法,而且是正确的 -列表是“给客户的某种超类型”),如果您要将其传递给仅向列表添加对象的方法,则可以使用上面的方法通用界限就足够了。
另一方面,如果您想从列表中检索对象并将其强类型键入为“客户”,那么您就不走运了,这是正确的。因为列表是一个列表List<Object>
,所以不能保证其中的内容是客户,因此您必须在检索时提供自己的演员表。(或者说真的,绝对,绝对要确保该列表仅包含Customers
并使用其他答案中的一个双播,但要意识到您完全避开了从泛型中获得的编译时类型安全性。案件)。
广义上讲,考虑编写方法时可以接受的最广泛的泛型界限总是很好的,如果将其用作库方法,则加倍。如果您只想从列表中读取内容,请使用List<? extends T>
而不是List<T>
,例如-这将使调用者可以传入的参数具有更大的作用域,这意味着它们不太可能遇到与您所遇到的类似的可避免问题在这里。