2017-06-29 57 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