我有3个班级:
class Class1 {}
class Class2 extends Class1 {}
class Class3 extends Class1 {}
我正在尝试更改包含Class1
的数组类型:
Class1[] arr = ... // [Class2, Class2, Class3, Class3]
arr = Arrays.copyOf(arr,2)
Class2[] arr2 = (Class2[]) arr
这似乎是不可能的,但我能做到
Class2[] arr2 = new Class2[arr.length]
for ...
arr2[i] = (Class2) arr[i]
有没有办法在没有迭代的情况下做到这一点?
我们可以假设arr
(copyOf
之后)中的所有元素都可以输入Class2
。
我得到的错误是:
CassCastException:[LStuff.Class1;无法转换为[LStuff.Class2;
答案 0 :(得分:5)
考虑到您想要更改所有对象的类型并尽可能将其放到另一个数组中;您可以将filter
与map
一起使用。
即:
Class2[] result = Arrays.stream(arr).filter(e -> e instanceof Class2)
.map(e -> (Class2)e).toArray(Class2[]::new);
答案 1 :(得分:3)
如果您确定数组的前两个元素具有所需类型,则可以在使用Arrays.copyOf
创建副本时请求相应的数组类型,即
Class1[] arr = ... // [Class2, Class2, Class3, Class3]
Class2[] arr2 = Arrays.copyOf(arr, 2, Class2[].class);
这不是Java-8特定的解决方案,但没有理由不惜一切代价尝试使用Java-8功能。如果您的假设不成立,上面的代码将抛出ClassCastException
,但是根据应用程序逻辑,这可能比根据类型过滤元素更好,并且在出现错误的情况下静默地继续使用与预期不同的内容
但是如果你想在运行时过滤元素,Stream API确实提供了最简洁的解决方案:
Class1[] arr = ... // [Class2, Class2, Class3, Class3]
Class2[] arr2 = Arrays.stream(arr)
.filter(Class2.class::isInstance).map(Class2.class::cast)
.toArray(Class2[]::new);
或
Class1[] arr = ... // [Class2, Class2, Class3, Class3]
Class2[] arr2 = Arrays.stream(arr)
.flatMap(o -> o instanceof Class2? Stream.of((Class2)o): null)
.toArray(Class2[]::new);
但请注意,这些解决方案包含的内容比实际需要的更多(这对于文档/可读性仍然有用)。 toArray
方法不要求结果数组类型是流的元素类型的超类型(因为Java Generics不支持表达此要求),因此,您不需要map
步骤:
Class2[] arr2 = Arrays.stream(arr).filter(Class2.class::isInstance).toArray(Class2[]::new);
这是过滤最简洁的解决方案。
答案 2 :(得分:2)
您不能将基类型转换为其子类型,否则您将获得异常。这样做:
Class2[] arr2 = new Class2[arr.length]
for ...
arr2[i] = (Class2) arr[i] // arr might contain different type of derrived class
与投射 class1 (基础)类型到 class2 (子)相同。所以,我认为问题的背景可能是错误的。
答案 3 :(得分:1)
首先来到这里:Class1[] arr = ...
arr
的元素以Class1
类型声明
这意味着这些元素不一定是Class2
个实例
因此,如果arr
没有引用Class2[]
对象,则在阵列转换期间可能会出现运行时错误。
例如,这可能会产生这种问题:
Class1[] arr = new Class1[5];
arr[0] = new Class1();
Class2[] arr2 = (Class2[]) arr; // exception at runtime [LClass1; cannot be cast to [LClass2;
您应该使用instanceof
检查而不是直接投票,例如:
Class2[] arr2 = (Class2[]) arr;
使用Java 8,您可以使用filter()
进行instanceof
检查并将其合并到toArray()
以创建Class2[]
数组:
Class1[] arr = new Class1[]{new Class1(), new Class2()};
Class2[] arr2 = Arrays.stream(arr)
.filter(e -> e instanceof Class2)
.toArray(Class2[]::new);
结果,您只有Class2
中的arr2
个实例。
答案 4 :(得分:0)
是的,如果你使用java8,你可以使用lambdas迭代并投射一个单行程。对于旧版本,您还可以使用Arrays.copyOf(...)
。
以下是类似问题的结果:casting Object array to Integer array error