将一个列表复制到另一个列表而不丢失原始列表的运行时类型
Copy a list to another list without losing the runtime type of original list
我想在不丢失运行时类型的情况下将 List<T>
复制到另一个列表。我想到的所有技术都无法实现这一点。
(此外,我不想简单地 return input
列表的引用,因为我不希望 input
列表中的编辑反映到复制的列表中)
下面列出了我尝试过的方法(查看所有 copy*
方法)。正如预期的那样,其中 none 使 (x.getClass() == y.getClass())
变为 true
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class TestX {
public static void main(String[] args) {
List<Integer> x = new LinkedList<>();
x.add(1);
x.add(2);
x.add(3);
List<Integer> y = copy2(x);
System.out.println("is runtime type equal? " + (x.getClass() == y.getClass()));
// I want (x.getClass() == y.getClass()) to be true
y.add(4);
System.out.println(x); // should be [1, 2, 3]
System.out.println(y); // should be [1, 2, 3, 4]
}
private static <T> List<T> copy0(List<T> input) {
return new ArrayList<>(input);
}
@SuppressWarnings("unchecked")
private static <T> List<T> copy1(List<T> input) {
Object[] x = input.toArray();
return (List<T>) List.of(x);
}
private static <T> List<T> copy2(List<T> input) {
return input.stream().collect(Collectors.toList());
}
private static <T> List<T> copy3(List<T> input) {
// Since Java 10
return List.copyOf(input);
}
}
最好的方法是让调用者发送一个函数来创建相同类型的新列表。另一种方法是使用反射,这将开始一系列危险的假设。
以下两个是根据您的代码复制实现的示例:
private static <T> List<T> copy0(List<T> input, Supplier<List<T>> newListCreator) {
List<T> newList = newListCreator.get();
newList.addAll(input);
return newList;
}
private static <T> List<T> copy2(List<T> input, Supplier<List<T>> newListCreator) {
return input.stream().collect(Collectors.toCollection(newListCreator));
}
你可以这样调用:
List<Integer> y = copy2(x, LinkedList::new);
LinkedList
不是 ArrayList
。如果您希望两种类型相等,那么您可以使用反射来调用实际调用的 class 的默认构造函数。类似于
private static <T> List<T> copy0(List<T> input) {
Class<?> cls = input.getClass();
try {
List<T> al = (List<T>) cls.getConstructor(null).newInstance(null);
Iterator<T> iter = input.iterator();
while (iter.hasNext()) {
al.add(iter.next());
}
return al;
} catch (Exception e) {
}
return null;
}
输出
is runtime type equal? true
当我用你的代码测试它时。请注意,这对构造函数做出了危险的假设,这不是我在实际项目中采用的方法。
这样试试,下面的代码忽略try... catch..
.
private static <T> List<T> copy2(List<T> input) {
List<T> instance = input.getClass().newInstance();
return input.stream().collect(Collectors.toCollection(() -> instance));
}
我想在不丢失运行时类型的情况下将 List<T>
复制到另一个列表。我想到的所有技术都无法实现这一点。
(此外,我不想简单地 return input
列表的引用,因为我不希望 input
列表中的编辑反映到复制的列表中)
下面列出了我尝试过的方法(查看所有 copy*
方法)。正如预期的那样,其中 none 使 (x.getClass() == y.getClass())
变为 true
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class TestX {
public static void main(String[] args) {
List<Integer> x = new LinkedList<>();
x.add(1);
x.add(2);
x.add(3);
List<Integer> y = copy2(x);
System.out.println("is runtime type equal? " + (x.getClass() == y.getClass()));
// I want (x.getClass() == y.getClass()) to be true
y.add(4);
System.out.println(x); // should be [1, 2, 3]
System.out.println(y); // should be [1, 2, 3, 4]
}
private static <T> List<T> copy0(List<T> input) {
return new ArrayList<>(input);
}
@SuppressWarnings("unchecked")
private static <T> List<T> copy1(List<T> input) {
Object[] x = input.toArray();
return (List<T>) List.of(x);
}
private static <T> List<T> copy2(List<T> input) {
return input.stream().collect(Collectors.toList());
}
private static <T> List<T> copy3(List<T> input) {
// Since Java 10
return List.copyOf(input);
}
}
最好的方法是让调用者发送一个函数来创建相同类型的新列表。另一种方法是使用反射,这将开始一系列危险的假设。
以下两个是根据您的代码复制实现的示例:
private static <T> List<T> copy0(List<T> input, Supplier<List<T>> newListCreator) {
List<T> newList = newListCreator.get();
newList.addAll(input);
return newList;
}
private static <T> List<T> copy2(List<T> input, Supplier<List<T>> newListCreator) {
return input.stream().collect(Collectors.toCollection(newListCreator));
}
你可以这样调用:
List<Integer> y = copy2(x, LinkedList::new);
LinkedList
不是 ArrayList
。如果您希望两种类型相等,那么您可以使用反射来调用实际调用的 class 的默认构造函数。类似于
private static <T> List<T> copy0(List<T> input) {
Class<?> cls = input.getClass();
try {
List<T> al = (List<T>) cls.getConstructor(null).newInstance(null);
Iterator<T> iter = input.iterator();
while (iter.hasNext()) {
al.add(iter.next());
}
return al;
} catch (Exception e) {
}
return null;
}
输出
is runtime type equal? true
当我用你的代码测试它时。请注意,这对构造函数做出了危险的假设,这不是我在实际项目中采用的方法。
这样试试,下面的代码忽略try... catch..
.
private static <T> List<T> copy2(List<T> input) {
List<T> instance = input.getClass().newInstance();
return input.stream().collect(Collectors.toCollection(() -> instance));
}