Java列表<;家长>;和列表<;儿童>;方法
假设我们有以下情况:Java列表<;家长>;和列表<;儿童>;方法,java,list,Java,List,假设我们有以下情况: public class Parent{ public void setXXX(String XXX); public String getXXX(); } public class Children extends Parent{ .... } public List<Something> cloneList(List<Something> original){ List<Something> newL
public class Parent{
public void setXXX(String XXX);
public String getXXX();
}
public class Children extends Parent{
....
}
public List<Something> cloneList(List<Something> original){
List<Something> newList=new ArrayList<>();
for(Something e:original){
Something newE=new Something();
newE.setXXX(e.getXXX());
newList.add(newE);
}
return newList;
}
现在我想创建一个名为clone List的方法,如下所示:
public class Parent{
public void setXXX(String XXX);
public String getXXX();
}
public class Children extends Parent{
....
}
public List<Something> cloneList(List<Something> original){
List<Something> newList=new ArrayList<>();
for(Something e:original){
Something newE=new Something();
newE.setXXX(e.getXXX());
newList.add(newE);
}
return newList;
}
公共列表克隆列表(列表原件){
List newList=newarraylist();
为了(某物e:原创){
新事物;
newE.setXXX(e.getXXX());
newList.add(newE);
}
返回newList;
}
问题是我们希望克隆列表可以同时应用于List
和List
,那么是否存在适用于“某物”的克隆列表呢
由于Java集合
与集合
不兼容,某些内容不能是“?扩展父项”或“父项”
假设:
1.不希望使用任何序列化方法或反射
将克隆列表的签名更改为:
public <X extends Parent> List<X> cloneList(final List<X> original)
公共列表克隆列表(最终列表原件)
然后它将工作,至少对于方法签名。您可以在内部构造一个
列表
,然后将其强制转换为列表
,如果需要,可以忽略警告;无法找到运行时类型“X”。您不能以这种方式使用泛型,只能使用反射
对于类型变量T
,不能使用new T()
。这是因为泛型是一种编译时机制,在运行时使用new
来创建特定的类型对象,而编译器无法在编译时创建对该类型的适当引用。因此,尽管如此:
new ArrayList<T>();
不是,因为编译器甚至不知道实际的类是什么(即使它只是被定义为
T extends Parents
,也可能是一个在程序编译时还没有编写过的类,比如孙子辈
或其他什么),甚至不知道它是否有无参数构造函数。这在Java中是不可能的。看一看
您可以如下更改您的方法,并使父类扩展SuperParent
public static <T extends SuperParent> List<T> cloneList(List<T> original, Class<T> type) throws IllegalAccessException, InstantiationException {
List<T> newList=new ArrayList<>();
for(T e : original){
T x = type.newInstance();
x.setXXX(e.getXXX());
newList.add(x);
}
return newList;
}
一般来说,您应该能够使用具有此签名的方法:
public <T extends Parent> List<T> cloneList(List<T> original)
因为不能保证类型参数T存在空构造函数。相反,您需要一个返回正确类型副本的方法。使用完全的类型安全性无法做到这一点,但您可以做到这一点。您可以实现以下方法:
public Parent Parent.copy();
public Children Children.copy();
。。。以任何合适的方式,然后像这样写下你的方法:
public <T extends Parent> List<T> cloneList(List<T> original) {
List<T> newList = new ArrayList<>();
for (T originalItem : original) {
newList.add(original.getClass().cast(original.copy()));
}
return newList;
}
公共列表克隆列表(列表原件){
List newList=newarraylist();
适用于(T原件:原件){
newList.add(original.getClass().cast(original.copy());
}
返回newList;
}
(请注意,尽管
Object.getClass()
的文档化返回类型是Class
,但它不适用于此目的,但声明返回类型实际上比这更具体,足以使此工作。)请考虑这样一个事实,即除非您将问题格式化为代码,否则无法在问题中使用括号。没有任何解决方案可以满足您添加的所有约束条件。要创建类静态未知的对象的忠实副本,需要使用反射或静态已知可用的方法。如果这些类上已经有了copy方法,那么您肯定会在示例代码中使用它。(请注意,Object.clone()
可能达到这个目的,但前提是类Parent
实现了Cloneable
。即使实现了,Object.clone()
,也可能会有很大的问题。)我更同意关于序列化的建议(或者可怕的clone
,但忘了我刚才说过的话),而不是基于反思的建议。首先,它假设存在一个无参数构造函数。其次,新副本虽然具有正确的类型,但不会具有原始副本的完整内部状态,这就是为什么首选序列化的原因。new T()不能使用code>不仅是因为空构造函数,还因为不能实例化类型变量。但更重要的是,如果类中有任何最终字段,则copy()
方法可能无法正确复制内部状态。需要一个复制构造函数,然后您需要为此使用getConstructor(…)
。@real我建议的copy()
方法不是将状态从一个对象复制到另一个对象,而是返回调用它的对象的副本。它可以用它需要的任何方式来做,包括调用复制构造函数。它不需要使用反射,因为它是对象类的实例方法,因此它知道使用什么构造函数以及如何实例化该类的对象。
public <T extends Parent> List<T> cloneList(List<T> original) {
List<T> newList = new ArrayList<>();
for (T originalItem : original) {
newList.add(original.getClass().cast(original.copy()));
}
return newList;
}