2017-06-29 38 views
2

是否可以使用原始对象中的属性创建新对象而不更改它?Java - 创建对象时无需更改原始对象

例如:

public void exampleTests() { 
     Tree t = Trees.makeTree(new int[]{2, 3, 4, 4, 1});//creating tree 
     assertTrue(t.contains(4)); //check if 4 is a node 
     assertFalse(t.contains(6));//check if 6 is a node 
     assertEquals(4, t.size()); //return size-nodes number (only different digits) 

     Tree t2 = t.add(6).add(7).add(6); // obj 2 take obj 1 and add 6 and 7 to it 
     assertFalse(t.contains(6)); // the first object should have no 6 
     assertTrue(t2.contains(6)); // the second object should have 6 

树木类:

public class Trees { 

    public static Tree makeTree(int[] elements) { 

     Tree tree = new Nodes(); 
     for (int i : elements) { 
      tree.add(i); 
     } 
     return tree; 
    } 

} 

树接口

public interface Tree { 


    public Tree add(int i); 

    public boolean contains(int i); 

    public int size(); 

    public String elementsAsString(); 

节点类:

public class Node { 
    int i; 
    Node left; 
    Node right; 

    public Node(int data) { 
     this.i = data; 
     left = null; 
     right = null; 
    } 
} 

节点类别:

public class Nodes implements Tree { 


    private Node root; 

    public Nodes() { 
     this.root = null; 
    } 

    @Override 
    public Nodes add(int i) { 
     root = insertNode(root, new Node(i)); 
     return new Nodes(); 
    } 

    private Node insertNode(Node currentParent, Node newNode) { 

     if (currentParent == null) { 
      return newNode; 
     } else if (newNode.i > currentParent.i) { 
      currentParent.right = insertNode(currentParent.right, newNode); 
     } else if (newNode.i < currentParent.i) { 
      currentParent.left = insertNode(currentParent.left, newNode); 
     } 
     return currentParent; 
    } 

我们在Java中称之为什么?

+0

在您的例子,你需要创建一个'add'方法它返回一个新的对象(即,在内部它需要注意创建一个新的'Tree'实例,其值为'this',通过'add'方法应该做什么调整。这里的关键字是“不可变数据结构”。 –

+0

@ C-Otto谢谢,我想在add方法中返回新的树,但它似乎将它们添加到不同的树 – james

回答

6

您需要创建原始对象的副本。做

一种方法是用一个拷贝构造函数:

public Tree (Tree other) { 
    // copy all the properties of other to the new object 
} 

然后改变

Tree t2 = t.add(6).add(7).add(6); 

Tree t2 = new Tree(t).add(6).add(7).add(6); 

注意的是,如果Tree成员包括引用类型(即引用其他对象),则必须决定是否创建这些ob的新副本也是。如果仅复制引用,则会得到原始对象的浅表副本,这可能会导致问题。

编辑:

由于它出现Tree是一个接口,你就必须建立在实现它的类定义拷贝构造函数:

public Nodes (Tree other) { 
    // copy all the properties of other to the new object 
} 

然后你就可以直接创建副本:

Tree t2 = new Nodes(t).add(6).add(7).add(6); 

或经由工厂方法:

Tree t2 = Trees.makeTree(t).add(6).add(7).add(6); 

其中makeTree是:

public static Tree makeTree(Tree source) { 

    Tree tree = new Nodes(source); 
    return tree; 
} 

注意public Nodes (Tree other)不完全是拷贝构造函数现在 - 这是不是一个拷贝构造函数更普遍,因为它可以接受Tree接口的任何实现并创建一个新Nodes实例包含相同的数据。

+0

感谢您的答案,有没有其他人可以d没有“新”这个词,就像它在上面的例子中一样? – james

+0

@james必须以某种方式创建新实例。您可以创建一个静态方法,以便调用看起来像'Trees.makeCopyOfTree(t)',但该方法必须在内部创建一个新的Tree实例。 – Eran

+0

看到我编辑的帖子请 – james

1

你会实现树为不变(意思是一次实例化对象不能改变),并创建在添加一个新的实例:

public Tree add(int node) { 
    // highly inefficient, assuming nodes are internally stored as an int array 
    // allocate new array + 1 size 
    int[] nodes = new int[this.nodes.length + 1]; 
    // copy this tree's nodes 
    System.arraycopy(this.nodes, 0, nodes, 0, this.nodes.length); 
    // add new node 
    nodes[nodes.length - 1] = node; 
    // return new tree instance 
    return new Tree(nodes); 
} 
+0

我可以用接口来做到吗?树接口节点类实现接口,创建新节点的节点类将其添加到节点 – james

+0

您可以详细说明吗?你的意思是一个接口“节点”与“添加(节点节点)”方法和“树实现节点”? –

+0

虐待编辑我的帖子添加我迄今为止所做的一切,我没有返回新的树没有工作 – james