我一直在尝试编写一种方法,该方法可以在嵌套时将通用数组展平。
private static <T> List<T> flatten(T[] in) {
List<T> result = new ArrayList<>();
for (T e : in) {
if (e.getClass().isArray()) {
result.addAll(Arrays.asList(e)); ## Issue is here.
} else {
result.add(e);
}
}
return result;
}
此代码不会导致任何错误,但也不起作用。当 e
不是数组时,事情会按预期工作...列表中会填充 in
的元素并返回。
但是,当e.getClass().isArray() == true
时,e
的元素不会被添加。相反,添加了原始数组,因此我最终得到了一个数组列表。
我的用例是我有一个正在传递泛型的方法 T[] someArray
public <T> void doSomeStuff(T[] someArray) {
Set<T> unique = Sets.newHashSet(someArray)
... do some stuff with the unique values ...
}
输入 someArray
可以嵌套也可以不嵌套(即 T
本身可能是一个数组,导致 T[][]
) 。我想确定输入中包含的唯一元素,无论它是否嵌套。将输入 someArray
传递给一组仅在未嵌套的情况下才有效,因此我试图展平。
所以我的问题是,我该如何做到这一点以及为什么我上面的方法不起作用?预先感谢您的教育。
最佳答案
您的代码无法运行。泛型就是不对齐。
假设您有一个由字符串和字符串数组组合而成的数组。 这不可能是 T[]
除非 T 是对象,这不是您想要的(因为这意味着您得到 List<Object>
。毕竟,如果 T
是 String
,那么您的输入数组是定义为 T[] in
,是一个 String[] in
,它不能包含字符串数组。毕竟,出于显而易见的原因, String[]
不是 String
的子类型。
不可能用泛型来描述“字符串数组,或字符串数组的数组,或字符串数组的数组的数组,等等”的概念。所以,泛型在这里没有地位。如果你想要这样,你可以“输入”的是“一个组件类型未知且混合的数组”,在java中是Object[]
(这是co/contra-variance明智的破坏,但这只是java规范的一部分:数组的方差不正确,已知问题且无法修复)。
这会给您带来第二个问题:泛型被删除,并且在该模型中您没有可以使用的实际类型。事实上,因为不可能使用泛型来告诉编译器对输入数组进行一些类型检查,所以编译器无法为您做任何事情,因此您想要的任何类型检查(并且您显然想要这样,您不这样做)不想返回 List of who knows what this is
),必须在运行时完成。
不幸的是,这也是不可能的 - 你无法在运行时检查某个对象是否是 Map<String, Integer>
。
所以,你想要的东西是不可能的。
如果您同意此方法只能完成具体类型的工作,那么这是可能的。也就是说,类型本身不包含任何 <>
。因此,如果您想获取“包含“字符串到整数的映射”和“字符串到整数的映射数组”组合的数组”,此方法将无法做到这一点,而且实际上是完全不可能的在java中做这样的事情。但是,如果您同意“包含字符串和字符串数组的组合的数组”,并希望将其转换为扁平化的字符串列表,那么这是可能的。
但是这很复杂:
public <T> List<T> flattenArray(Class<T> type, Object[] in) {
if (type.isArray()) throw new IllegalArgumentException();
var out = new ArrayList<T>();
flattenArray0(type, in, out);
return out;
}
private <T> void flattenArray0(Class<T> type, Object[] in, List<T> out) {
for (Object a : in) {
if (a == null) {
out.add(null);
} else if (a.getClass().isArray()) {
flattenArray0(type, (Object[]) a, out);
} else {
out.add(type.cast(a));
}
}
}
实际操作:
Object[] test = new Object[3];
test[0] = "Hello";
test[1] = new String[] {"Foo", "Bar"};
Object[] threeDeep = new Object[2];
test[2] = threeDeep;
threeDeep[0] = "Goodbye";
threeDeep[1] = new String[] {"Baz"};
List<String> result = flattenArray(String.class, test);
System.out.println(result);
应该打印:["Hello", "Foo", "Bar", "Goodbye", "Baz"]
。
关于java - 展平通用数组的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68423209/