如何在java数组中将类型更改为扩展对象?

时间:2017-10-28 18:18:43

标签: java java-8

我有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]

有没有办法在没有迭代的情况下做到这一点?

我们可以假设arrcopyOf之后)中的所有元素都可以输入Class2

我得到的错误是:

  

CassCastException:[LStuff.Class1;无法转换为[LStuff.Class2;

5 个答案:

答案 0 :(得分:5)

考虑到您想要更改所有对象的类型并尽可能将其放到另一个数组中;您可以将filtermap一起使用。 即:

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