Java 克隆由内部类定义的对象

Java 克隆由内部类定义的对象,java,clone,inner-classes,instance-variables,Java,Clone,Inner Classes,Instance Variables,我将这个向量定义为实例变量,也定义为内部类: private Vector<MATIdentifier> matIds = new Vector<MATIdentifier>(){ @Override public boolean add(MATIdentifier mi){ if(this.contains(mi)){ return false; } super.add(mi)

我将这个向量定义为实例变量,也定义为内部类

private Vector<MATIdentifier> matIds = new Vector<MATIdentifier>(){

     @Override
    public boolean add(MATIdentifier mi){


     if(this.contains(mi)){

            return false;

          }
      super.add(mi);
      return true;

 }

   @Override
   public boolean contains(Object o){

         if(o instanceof MATIdentifier){


            for(MATIdentifier mi: this){

                if(mi.getIdValue().equals(((MATIdentifier)o).getIdValue())){

                 return true;

                }
           }
        }
                return false;

      }

};
private Vector matIds=new Vector(){
@凌驾
公共布尔加法(MATIdentifier mi){
如果(本文件包含(mi)){
返回false;
}
super.add(mi);
返回true;
}
@凌驾
公共布尔包含(对象o){
if(o材质标识符的实例){
对于(MATIdentifier mi:此){
如果(mi.getIdValue().equals((MATIdentifier)o.getIdValue()){
返回true;
}
}
}
返回false;
}
};
在程序的后面,我想从数据库中填充这个向量。创建这个Vector类的新实例会更好,而不是简单地删除所有元素并重用同一个对象——我想我可以做到,但我仍然想知道克隆对象的方法

我知道的唯一方法就是克隆()这个对象。这安全吗?它会克隆被重写的方法add(MATIdentifier)和contains(Object)吗

也许我也应该覆盖clone()。。。?或者Vector中预定义的clone()方法是否足够


注意:我把@Override注释放在自己的身上,Java编译器(Eclipse)出于某种原因没有让我这么做。

这个问题涉及Java中的几个概念

首先,我想问一下,如果你想保证唯一性,为什么你不使用一个

接下来是克隆方法。克隆是原始数据结构的一个还是一个?如果我们看一下,它告诉我们:

返回此向量的克隆。副本将包含对 内部数据数组的克隆,而不是对原始数据数组的引用 此向量对象的内部数据数组

因此我们可以从中了解到,首先,它还克隆了内部数据,因此这意味着一个深度拷贝。现在,它是否也复制被重写的方法?对这一点的快速测试告诉我,是的,确实如此

最后,如何测试这一点?我建议您使用像junit这样的单元测试框架。 以下是如何使用此框架确保假设正确的示例:

package test.good;

import static org.junit.Assert.*;

import java.util.Vector;

import org.junit.Before;
import org.junit.Test;

public class CloneTest {

    private Vector<MATIdentifier> matIds;

    MATIdentifier id1 = new MATIdentifier("first");
    MATIdentifier id2 = new MATIdentifier("second");
    MATIdentifier id3 = new MATIdentifier("third");
    MATIdentifier idDuplicate = new MATIdentifier("first");

    @Before
    public void prepare() {
        matIds = new Vector<MATIdentifier>() {
            @Override
            public boolean add(MATIdentifier mi) {
                if (this.contains(mi)) {
                    return false;
                }
                super.add(mi);
                return true;
            }

            @Override
            public boolean contains(Object o) {
                if (o instanceof MATIdentifier) {
                    for (MATIdentifier mi : this) {
                        if (mi.getIdValue().equals(((MATIdentifier) o).getIdValue())) {
                            return true;
                        }
                    }
                }
                return false;
            }
        };
    }

    private void populateVector(Vector<MATIdentifier> vector) {
        vector.add(id1);
        vector.add(id2);
        vector.add(id3);
    }

    /**
     * Tests that adding new values returns true, and adding duplicates returns
     * false, and that the duplicates are not actually added
     */
    @Test
    public void testDuplicateFails() {
        boolean added;
        added = matIds.add(id1);
        assertTrue(added);
        added = matIds.add(id2);
        assertTrue(added);
        added = matIds.add(idDuplicate);
        assertFalse(added);
        assertEquals(2, matIds.size());
    }

    @Test
    public void testDeepCopy() {
        // Start with by pupulating our customized vector
        populateVector(matIds);
        assertEquals(3, matIds.size());
        // Clone the vector
        Vector<MATIdentifier> clone = (Vector<MATIdentifier>) matIds.clone();
        assertEquals(3, clone.size());
        // remove something from the original
        matIds.remove(2);
        assertEquals(3, clone.size());
        assertEquals(2, matIds.size());
        // add something to the original
        matIds.add(new MATIdentifier("New Value"));
        assertEquals(3, clone.size());
        assertEquals(3, matIds.size());
        // add a duplicate to the clone, to ensure that the overridden behavior
        // is present in the clone
        boolean added = clone.add(id1);
        assertFalse(added);

    }

}

class MATIdentifier {
    private String idValue;

    public MATIdentifier(String idValue) {
        this.idValue = idValue;
    }

    public String getIdValue() {
        return idValue;
    }

    public void setIdValue(String idValue) {
        this.idValue = idValue;
    }

}
package test.good;
导入静态org.junit.Assert.*;
导入java.util.Vector;
导入org.junit.Before;
导入org.junit.Test;
公共类克隆测试{
私有向量矩阵;
MATIdentifier id1=新MATIdentifier(“第一”);
MATIdentifier id2=新的MATIdentifier(“第二个”);
MATIdentifier id3=新MATIdentifier(“第三”);
MATIdentifier idDuplicate=新MATIdentifier(“第一”);
@以前
公众假期准备(){
matIds=新向量(){
@凌驾
公共布尔加法(MATIdentifier mi){
如果(本文件包含(mi)){
返回false;
}
super.add(mi);
返回true;
}
@凌驾
公共布尔包含(对象o){
if(o材质标识符的实例){
对于(MATIdentifier mi:此){
如果(mi.getIdValue().equals((MATIdentifier)o.getIdValue()){
返回true;
}
}
}
返回false;
}
};
}
私有void populateVector(向量向量){
矢量加法(id1);
矢量加法(id2);
矢量加法(id3);
}
/**
*测试添加新值返回true,添加重复值返回true
*false,并且没有实际添加重复项
*/
@试验
公共void testDuplicateFails(){
布尔加法;
added=matIds.add(id1);
资产净值(新增);
added=matIds.add(id2);
资产净值(新增);
added=matIds.add(idreplicate);
资产虚假(增加);
assertEquals(2,matIds.size());
}
@试验
公共void testDeepCopy(){
//首先,对我们定制的向量进行优化
大众媒介(MATID);
assertEquals(3,matIds.size());
//克隆载体
向量克隆=(向量)matIds.clone();
assertEquals(3,clone.size());
//从原稿中删除某些内容
移除(2);
assertEquals(3,clone.size());
assertEquals(2,matIds.size());
//在原来的基础上增加一些东西
添加(新的MATIdentifier(“新值”));
assertEquals(3,clone.size());
assertEquals(3,matIds.size());
//向克隆添加副本,以确保覆盖的行为
//存在于克隆中
boolean added=clone.add(id1);
资产虚假(增加);
}
}
类别识别器{
私有字符串idValue;
公共数据标识符(字符串idValue){
this.idValue=idValue;
}
公共字符串getIdValue(){
返回idValue;
}
公共void setIdValue(字符串idValue){
this.idValue=idValue;
}
}
另外,与为向量创建自定义包含和添加impl相比,重写MATIdentifier上的equals操作或创建MATIdentifier可能是更好的做法。我真的建议您使用java.util.Set。
另外,使用我认为很重要的功能创建这样的匿名内部类型并不是一种好的做法,因为这会使代码更难测试。如果您坚持继续使用专门的向量实现,您应该将其移动到类中。

与使用Java Set相反,这样我相信我会知道用户(或程序员)是否尝试检查向量是否包含非MATIdentifier类型。如果类型不是MATIdentifier,我可以在contains方法中放置一个print或logging语句。另外,正如您所说,我必须至少重写java.util.Set中的equals(Object)。我猜在集合中将覆盖相等