Java 如何在构造函数中复制对象(而不是对象引用)
我有一个相当简单的POJO:Java 如何在构造函数中复制对象(而不是对象引用),java,list,unit-testing,constructor,pojo,Java,List,Unit Testing,Constructor,Pojo,我有一个相当简单的POJO: class POJO { private final int id; private final List<Name> names; //Name is another POJO POJO(final int id, final List<Name> names) { this.id = id; this.names = names; } public int getId()
class POJO
{
private final int id;
private final List<Name> names; //Name is another POJO
POJO(final int id, final List<Name> names)
{
this.id = id;
this.names = names;
}
public int getId() { return id; }
public List<Name> getNames() { return names; }
}
类POJO
{
私有最终int id;
私有最终列表名称;//名称是另一个POJO
POJO(最终整数id、最终列表名称)
{
this.id=id;
this.names=名称;
}
public int getId(){return id;}
public List getNames(){return names;}
}
POJO的名称如下所示:
class Name
{
private final String firstName;
private final String lastName;
POJO(final String firstName, final List<Name> names)
{
this.firstName = firstName;
this.lastName = lastName;
}
public int getFirstName() { return firstName; }
public int getLastName() { return lastName; }
}
类名
{
私有最终字符串名;
私有最终字符串lastName;
POJO(最终字符串名、最终列表名)
{
this.firstName=firstName;
this.lastName=lastName;
}
public int getFirstName(){return firstName;}
public int getLastName(){return lastName;}
}
类POJO存储对名称列表的引用。为了安全起见,我想复制一份检索到的列表。为此,我尝试将构造函数修改为
this.names = new ArrayList<>();
this.names.addAll(names);
this.names=new ArrayList();
this.names.addAll(名称);
这是我的测试:
public class POJOTest
{
private final int id = 1;
private final List<Name> names = Mockito.mock(List.class);
private final POJO target = new POJO(id, names);
@Test
public void testGetMethods()
{
Assert.assertEquals(id, target.getId());
Assert.assertEquals(names, target.getNames());
}
}
公共类POJOTest
{
私有最终int id=1;
私有最终列表名称=Mockito.mock(List.class);
私有最终POJO目标=新POJO(id、名称);
@试验
公共void testGetMethods()
{
Assert.assertEquals(id,target.getId());
Assert.assertEquals(name,target.getNames());
}
}
我的测试用例失败了
java.lang.NullPointerException
at java.util.ArrayList.addAll(ArrayList.java:582)
at POJO.<init>(POJO.java:38)
at POJOTest.<init>(POJOTest.java:17)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
java.lang.NullPointerException
在java.util.ArrayList.addAll(ArrayList.java:582)
在POJO(POJO.java:38)
POJOTest.(POJOTest.java:17)
位于sun.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法)
位于sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
在sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
位于java.lang.reflect.Constructor.newInstance(Constructor.java:423)
位于org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
位于org.junit.runners.BlockJUnit4ClassRunner$1.runReflectCall(BlockJUnit4ClassRunner.java:266)
位于org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
位于org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
位于org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
位于org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
位于org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
访问org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
位于org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
位于org.junit.runners.ParentRunner.run(ParentRunner.java:363)
位于org.junit.runner.JUnitCore.run(JUnitCore.java:137)
位于com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
位于com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
位于com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
位于com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
这是java:582:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
public boolean addAll(Collection根据您的问题,不清楚要将名称列表的副本存储在何处。
我在POJO类中创建了一个副本,这样POJO类的每个实例都有自己的名称列表副本
package test;
import java.util.ArrayList;
import java.util.Iterator;
public class POJO {
private final int id;
private final ArrayList<Name> names; //Name is another POJO
private ArrayList<Name> namescopy;
POJO(int id, ArrayList<Name> names)
{
this.id = id;
this.names = names;
namescopy = new ArrayList<Name>();
Iterator<Name> it = names.iterator();
while(it.hasNext()) {
try { namescopy.add( (Name) it.next().clone()); } catch (CloneNotSupportedException e) {e.printStackTrace();}
}
}
public int getId() { return id; }
public ArrayList<Name> getNames() { return names; }
public ArrayList<Name> getNamesCopy() {
return namescopy;
}
}
封装测试;
导入java.util.ArrayList;
公共类POJOTest{
公共静态void main(字符串[]args){
姓名a=新姓名(“威尔”、“史密斯”);
姓名b=新姓名(“布鲁斯”、“韦恩”);
名称c=新名称(“威尔”、“特纳”);
ArrayList namelist=新的ArrayList();
名单。增加(a);
名单。增加(b);
名单。添加(c);
POJO p=新POJO(1,名称列表);
p、 getNames().forEach(i->System.out.println(i.getFirstName()+“”+i.getLastName()+“”+i));
System.out.println();
p、 getNamesCopy().forEach(i->System.out.println(i.getFirstName()+“”+i.getLastName()+“”+i));
}
}
您看过ArrayList.java:582了吗?您认为什么引用是空的?请在您的问题中包括您的测试用例和POJO构造函数的实际代码。我已经添加了更多的细节。现在您已经看过addAll的代码了,您知道NPE的直接原因是什么吗?也就是说,哪个取消引用导致了NPE?学习这一点很重要。我不确定。'names'是否为null?第582行是int numNew=a.length
,因此我们怀疑c.toArray()的结果为null。你能明白为什么吗?c在这一点上有什么值?在模拟上调用方法时会发生什么?
package test;
public class Name implements Cloneable {
private final String firstName ;
private final String lastName;
Name( String firstName, String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public Object clone() throws
CloneNotSupportedException
{
return super.clone();
}
}
package test;
import java.util.ArrayList;
public class POJOTest {
public static void main(String[] args) {
Name a = new Name("Will", "Smith");
Name b = new Name("Bruce", "Wayne");
Name c = new Name("Will", "Turner");
ArrayList<Name> namelist = new ArrayList<Name>();
namelist.add(a);
namelist.add(b);
namelist.add(c);
POJO p = new POJO(1, namelist);
p.getNames().forEach(i -> System.out.println(i.getFirstName()+" "+i.getLastName() +" "+ i));
System.out.println();
p.getNamesCopy().forEach(i -> System.out.println(i.getFirstName()+" "+i.getLastName() +" "+ i));
}
}