2013-08-24 69 views
1

我知道对java中对象的引用是通过复制传递的,但副本仍然指向系统中的同一内存,所以在更新另一个函数中的复杂对象的某些数据之后,应该维护原始数据。但有趣的是,这里出了问题。我正在与Tries合作。丢失数据的复杂对象

这里是我的执行线索的,这是因为一些自定义的规则相当定制的实现:

public class Trie { 
    boolean isEnd; 
    Trie trie[] = new Trie[256]; 
    ArrayList<Integer> indexNode; 

    public static Trie createTrieNode() { 
     Trie temp = new Trie(); 
     temp.isEnd = false; 
     temp.indexNode = new ArrayList<Integer>(); 
     for (int i = 0; i < temp.trie.length; i++) { 
      temp.trie[i] = null; 
     } 

     return temp; 
    } 

    public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) { 
     if (root == null) 
      root = createTrieNode(); 
     if (i < alpha.length) 
      insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1); 
     else { 
      if (root.isEnd == true) { 
       root.indexNode.add(index); 
      } else { 
       root.isEnd = true; 
       root.indexNode.add(index); 
      } 
     } 

    } 

} 

现在我的目标root来自这个类并在调试,我可以看到正在执行该语句:root.isEnd = true;

类:

public class AnagramsTogether { 
     public Trie root = new Trie(); 
     public void printAnagrams(String[] anagrams){ 
      char[] buffer; 
      for (int i = 0; i < anagrams.length; i++) { 
       buffer = anagrams[i].toCharArray(); 
       Arrays.sort(buffer); 
       Trie.insertIntoTrie(root, buffer, i, 0); 
      } 
      AnagramsUtil.anagramUtil(root,anagrams); 
     } 
    } 

但当时root这里传递的是AnagramsUtil.anagramUtil(root,anagrams);

public class AnagramsUtil { 

    public static void anagramUtil(Trie root, String[] anagrams) { 

     if (root.isEnd == true) { 

      for (Iterator<Integer> iterator = root.indexNode.iterator(); iterator 
        .hasNext();) { 
       Integer integer = (Integer) iterator.next(); 
       System.out.println(anagrams[integer]); 
      } 
     } else { 
      for (int i = 0; i < root.trie.length; i++) { 
       if (root.trie[i] == null) 
        continue; 
       anagramUtil(root.trie[i], anagrams); 
      } 
     } 
    } 

} 
public class Anagram{ 
        public static String string[] = {"cat", "dog", "god","act", "tac","gdo"}; 
        public static void main(String args){ 
         new AnagramsTogether().printAnagrams(Anagram.string); 
       } 
} 

本声明if (root.isEnd == true)从不执行,所以是这是从来没有执行anagramUtil(root.trie[i], anagrams);。该程序只是继续执行continue声明。 不应该是这种情况,因为我已经看到root.trie[i]正在接收值。为什么会发生这种情况?我对java很陌生。

+0

[This](http://stackoverflow.com/a/40523/645270)可以帮助 – keyser

+0

调用'printAnagrams(String [] anagrams)'时使用了哪些参数? –

+0

用参数编辑我的代码。 –

回答

0

你的程序中有很多Trie对象,你很困惑它们。如果使用调试器检查对象标识(对象编号),则会看到它们不相同。

+0

是的,我确实看到了id不一样。为什么会发生? –

0

你说的是你在调试器中看到要执行的语句root.isEnd = true;,但是你没有提到哪个对象正在执行。

insertIntoTrie()方法被称为递归这样,这种说法可能是对Trie对象的root在其trie[]数组,但不能为root对象本身执行。

由于实际执行取决于您用来呼叫printAnagrams(String[] anagrams)的参数,如果您需要更具体的答案,请将这些参数添加到您的问题中。

更新:好您编辑您的问题后,很明显,你可以将这个错误被滥用的对象引用,即使你知道,所有“......在Java对象的引用是通过复制传递” 。您的insertIntoTrie()有问题。看起来你打算创建一个新对象,如果参数rootnull但是新对象将会丢失,因为root参数是副本。如果您打印原始root对象(AnagramsTogether类中的对象)的整个trie[]成员,则在方法结束时,您会看到所有对象都是null

0

在Java中,null不是一个对象,它只是一个特殊类型。因此null还没有一个参考。因此,例如:

Trie root = null; 
insertIntoTrie(root, alpha, index, i); 
// after called this function, root = null 

调用此函数后,root仍然是null,因为变量root尚未调用此函数之前的对象。所以没有任何参考变量root要通过副本传递给这个调用。

解决方案

更改您的功能:

public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) { 
    if (root == null) 
     root = createTrieNode(); 
    if (i < alpha.length) 
     insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1); 
    else { 
     if (root.isEnd == true) { 
      root.indexNode.add(index); 
     } else { 
      root.isEnd = true; 
      root.indexNode.add(index); 
     } 
    } 

} 

分为:

public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) { 
    if (i < alpha.length) { 
     if (root.trie[alpha[i] - 'a'] == null) { 
      root.trie[alpha[i] - 'a'] = createTrieNode(); 
     } 
     insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1); 
    } 
    else { 
     if (root.isEnd == true) { 
      root.indexNode.add(index); 
     } else { 
      root.isEnd = true; 
      root.indexNode.add(index); 
     } 
    } 

} 

该解决方案确保了root总是传递给insertIntoTrie(...)函数之前的对象。