public static <T> List<T> templatizeList(final List list, final Class<T> clazz) {
return (List<T>) list;
}
public static <T> List<T> typeSafeAdd(List<?> from, Class<T> clazz) {
List<T> to = new ArrayList<>();
from.forEach(item -> to.add(clazz.cast(item)));
return to;
}
这两种方法有什么区别?一种方式比另一方更安全或更快还是没关系?
答案 0 :(得分:6)
根据Java文档,泛型仅限于编译时。一旦代码编译,它们就会消失,这称为Type Erasure。
现在,关于方法,方法1只是在列表中添加一个强制转换而不检查其中存在的所有元素的类型。这意味着,如果List被转换为Cat类型,那么在运行时代码中的任何地方都可能会出现意外的ClasscastException,而它的内容是Dog。
方法2创建一个全新的列表,它遍历所有元素并尝试将每个元素转换为目标类型。意思是,如果无法将所有元素强制转换为目标类型,则会失败。
我认为方法2是安全的,因为它确保在添加演员表之前一切正常(即本地化风险)。方法1可以允许List(包含Cat,Dog,Dinosaur)被转换为List&lt;猫&gt;然后,你可能会遇到意外的失败。
This example解释得很清楚。
答案 1 :(得分:2)
鉴于讨论,我想建议一个结合了两个世界中最好的选项:它既可以本地化不安全演员的风险又它可以避免创建新的List。这很容易。 (我正在制作这个社区维基,因为我只是借用别人的想法。)
第1步:对方法2中的每个元素进行强制转换。不要对结果执行任何操作,只需执行强制转换。这将确保预先发现不良价值。
第2步:执行方法1中的List
强制转换。
如果知道你从Hibernate获得的List
只包含正确类型的元素,那么你可以继续使用方法1.(Eclipse JDT(至少在之前) Mars)在AST中做同样的事情。我必须经常处理原始类型。)
答案 2 :(得分:1)
不同之处在于,在第一个中您返回相同的列表,而第二个创建一个新列表。
我认为没有更安全的&#39;两者之间 - 因为它最终在两者上都抛出了所有列表对象,非T对象将导致两者都出现classCastException。
第一个在我看来更好 - 不是创建一个相当多余的新列表
答案 3 :(得分:1)
无法确定List是否真的应该具有通用参数。您必须事先知道参数应该是什么(或者您在获得ClassCastException时会发现)。这就是代码生成警告的原因,因为编译器可能无法知道它是否安全。
如果要支持更通用的数据类型, 那么你可以选择
public static <T> List<?> templatizeList(final List list, final Class<T> clazz) {
return (List<?>) list;
}
否则, 第二个选项确保它始终是相同的类型,但它创建新的List对象...
因此,如果您确定使用第一个解决方案或我的第一个选项,否则您的第二个解决方案是正确删除正在创建新对象的部分。