我有一个向量,我将其定义为实例变量和内部类:
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;
}
};
在程序的后面,我想从数据库中填充这个向量。最好创建一个Vector类的新实例,而不是简单地删除所有元素并重用同一个对象——我想我可以做到,但我仍然想知道克隆对象的方法。
我知道如何做到这一点的唯一方法是克隆()这个对象。这安全吗?它会克隆覆盖的方法add(MATIDENTIER)和contains(Object)吗?
也许我也应该覆盖clone()。。。?或者Vector中预定义的clone()方法是否足够?
注意:我自己放了@Override注释,Java编译器(Eclipse)出于某种原因没有让我这么做。
这个问题涉及Java中的几个概念。
首先,我想问一下,如果您想保证唯一性,为什么不使用java.util.Set?
接下来是克隆方法。克隆是原始数据结构的浅拷贝还是深拷贝?如果我们看一下Oracle的Vector API文档,它告诉我们:
返回此矢量的克隆。副本将包含对内部数据阵列的克隆,而不是对原始阵列的引用此Vector对象的内部数据数组。
因此,我们可以从中了解到,首先,它还克隆了内部数据,因此这表明存在深度复制。现在,它是否也复制了重写的方法?一个快速的测试这个告诉我,是的,它确实。
最后,如何测试这一点?我建议您使用像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;
}
}
PS,重写MATIdentifier上的equals操作或创建MATIdentifier Comparator可能比为Vector创建自定义包含和添加impl更好。我真的建议你使用java.util.Set。此外,使用我认为重要的功能创建这样的匿名内部类型并不是一个好的做法,因为这会使代码更难测试。如果您坚持要继续使用一个专门的Vector实现,那么您应该将它移到一个类中。