如何在构造函数中复制对象(而不是对象引用)

时间:2020-10-05 02:48:09

标签: 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() { return id; }
 public List<Name> 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; }
}

POJO类存储对Name列表的引用。为了安全起见,我想复制检索到的列表。为此,我尝试将构造函数修改为

this.names = new ArrayList<>();
this.names.addAll(names);

这是我的测试

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());
    }
}

我的测试用例失败

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: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;
    }

我在这里做错了什么?还有其他方法可以在构造函数中进行复制吗?

1 个答案:

答案 0 :(得分:0)

根据您的问题,不清楚您要在哪里存储名称列表的副本。 我在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;
     }
}

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));
     }
}

相关问题