如何将List <Object>转换为List <MyClass>
这不编译,任何build议表示赞赏。
... List<Object> list = getList(); return (List<Customer>) list;
编译器说:不能强制List<Object>
为List<Customer>
您可以将任何对象先转换为Object,然后将其转换为任何types。 在你的情况下:
(List<Customer>)(Object)list;
您必须确保在运行时该列表除了包含Customer对象外没有任何内容。
批评者说,这样的投射表明你的代码有问题; 你应该能够调整你的types声明来避免它。 但是Javagenerics太复杂了,并不完美。 有时候,你只是不知道是否有一个漂亮的解决scheme来满足编译器的要求,即使你非常了解运行时types,而且你知道你所要做的是安全的。 在这种情况下,只要按照需要进行粗铸,就可以把工作留给家里。
这是因为虽然客户是一个对象,客户列表不是对象列表。 如果是这样,那么你可以把任何对象放在客户列表中。
根据您的其他代码,最佳答案可能会有所不同。 尝试:
List<? extends Object> list = getList(); return (List<Customer>) list;
要么
List list = getList(); return (List<Customer>) list;
但是请记住,不build议这样不加控制的强制转换。
您可以使用双重播放。
return (List<Customer>) (List) getList();
使用Java 8 Streams :
有时蛮力铸造是好的:
List<MyClass> mythings = (List<MyClass>) (Object) objects
但是,这是一个更通用的解决scheme:
List<Object> objects = Arrays.asList("String1", "String2"); List<String> strings = list.stream() .map(element->(String) element) .collect(Collectors.toList());
有很多好处,但是一个是,如果你不能确定它包含什么,你可以更优雅地列出你的列表:
list.stream() .filter(element->element instanceof String) .map(element->(String)element) .collect(Collectors.toList());
请注意,我不是Java程序员,但在.NET和C#中,此function称为逆变或协方差。 我还没有深入研究这些东西,因为它们在.NET 4.0中是新的,我不使用,因为它只是testing版,所以我不知道这两个术语中哪一个描述了你的问题,但是让我描述一下与此有关的技术问题。
假设你被允许投。 请注意,我说过,因为这就是你所说的,但是有两种可能的操作,即投射和转换 。
转换意味着你得到一个新的列表对象,但是你说铸造,这意味着你想临时对待一个对象作为另一种types。
这是这个问题。
如果允许以下情况会发生什么(注意,我假设在投射之前,对象列表实际上只包含Customer对象,否则即使在这个假想的Java版本中投射也不起作用):
List<Object> list = getList(); List<Customer> customers = (List<Customer>)list; list.Insert(0, new someOtherObjectNotACustomer()); Customer c = customers[0];
在这种情况下,这会试图将一个不是客户的对象看作是一个客户,并且会在列表中或者从任务中得到一个运行时错误。
generics,但是,应该给你types安全的数据types,如集合,因为他们喜欢扔“保证”一词,这种types的演员,随之而来的问题,是不允许的。
在.NET 4.0中(我知道,你的问题是关于java的),这将被允许在一些非常特殊的情况下 ,编译器可以保证你所做的操作是安全的,但是从一般意义上讲,这种types的转换不会被)允许。 对于java来说也是一样,尽pipe我不确定是否有任何计划将Java语言和Java语言混为一谈。
希望有比我更好的java知识的人可以告诉你java未来或实现的细节。
您应该遍历列表并逐个投射所有对象
你不能因为List<Object>
和List<Customer>
不在同一个inheritance树中。
您可以添加一个新的构造函数到您的List<Customer>
类中,它接受一个List<Object>
,然后遍历列表将每个Object
投射到一个Customer
并将其添加到您的集合中。 请注意,如果调用者的List<Object>
包含非Customer
某个东西,则可能会发生无效的转换exception。
generics列表的要点是将它们限制到某些types。 您正在尝试列出可以包含任何内容的订单(订单,产品等),并将其列入只能带客户的列表。
最好的办法是创build一个新的List<Customer>
,迭代List<Object>
,将每个项目添加到新列表中,然后返回。
正如其他人指出的那样,由于List<Object>
不是List<Customer>
,所以不能保存转换。 你可以做的是在列表中定义一个视图,进行就地types检查。 使用Google Collections :
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;
这是合法的(好吧,不仅仅是合法的,而且是正确的 – 这个列表是“给客户的一些超types”),如果你打算把它传递给一个仅仅添加对象到列表中的方法,那么上面的通用边界就足够了。
另一方面,如果你想从列表中检索对象,并将它们强制input为Customers,那么你的运气不好,这是正确的。 因为列表是一个List<Object>
所以不能保证内容是客户,所以你必须提供你自己的检索。 (或者真的,绝对的,加倍确定列表将只包含Customers
并使用来自其他答案之一的双重播放,但要意识到,你完全规避了编译时types – 从generics中获得的安全性这个案例)。
从广义的angular度来说,考虑写一个方法时可以接受的最广泛的generics边界总是好的,如果将要被用作库方法,则是双倍的。 如果你只是要从列表中读取,使用List<? extends T>
List<? extends T>
而不是List<T>
,这使得调用者可以传入更多的参数,这意味着他们不太可能遇到类似于这里的可避免的问题。
与上面的Bozho类似。 你可以通过这个方法在这里做一些解决方法(虽然我自己不喜欢它):
public <T> List<T> convert(List list, T t){ return list; }
是。 它会将您的列表投入您所要求的genericstypes。
在上面给出的情况下,你可以做一些这样的代码:
List<Object> list = getList(); return convert(list, new Customer());
不是最有效的方法,但是:
List<Customer> customers = new ArrayList<Customers>(getList());
另一种方法是使用Java 8stream。
List<Customer> customer = myObjects.stream() .filter(Customer.class::isInstance) .map(Customer.class::cast) .collect(toList());
您可以创build一个新的列表并添加元素:
例如:
List<A> a = getListOfA(); List<Object> newList = new ArrayList<>(); newList.addAll(a);
你可以做这样的事情
List<Customer> cusList = new ArrayList<Customer>(); for(Object o: list){ cusList.add((Customer)o); } return cusList;
或者Java 8的方式
list.stream().forEach(x->cusList.add((Customer)x)) return cuslist;