Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 序列化二叉树时的StackOverflowException_Java_Android_Serialization_Binary Tree - Fatal编程技术网

Java 序列化二叉树时的StackOverflowException

Java 序列化二叉树时的StackOverflowException,java,android,serialization,binary-tree,Java,Android,Serialization,Binary Tree,我正在尝试为Android应用程序实现一个二叉树,我希望能够将其序列化到设备上的一个文件中。不幸的是,我在尝试序列化它时遇到了stackoverflow错误 代码: class BTree<V extends Model> implements Serializable { /** * */ private static final long serialVersionUID = 4944483811730762415L; private V value; private B

我正在尝试为Android应用程序实现一个二叉树,我希望能够将其序列化到设备上的一个文件中。不幸的是,我在尝试序列化它时遇到了stackoverflow错误

代码:

class BTree<V extends Model> implements Serializable {
/**
 * 
 */
private static final long serialVersionUID = 4944483811730762415L;

private V value;
private BTree<V> left;
private BTree<V> right;

public BTree(V value) {
    this.value = value;
}

public BTree(V value, BTree<V> left, BTree<V> right) {
    this.value = value;
    this.left = left;
    this.right = right;
}

private int getValue() {
    return this.value.hashCode();
}

public void insert(BTree<V> node) {     
    if (this.getValue() >= node.getValue()) {
        if (this.left == null) {
            this.left = node;
        } else {
            this.left.insert(node);
        }
    } else {
        if (this.right == null) {
            this.right = node;
        } else {
            this.right.insert(node);
        }
    }
}

public boolean containsKey(Object key) {
    return this.find(key) != null;
}

public V find(Object key) {
    if (key.hashCode() == this.getValue()) {
        return this.value;
    } else if (key.hashCode() > this.getValue() && this.left != null) {
        return this.left.find(key);
    } else if (key.hashCode() < this.getValue() && this.right != null) {
        return this.right.find(key);
    } else {
        return null;
    }
}

public ArrayList<V> getAllValues() {
    ArrayList<V> values = new ArrayList<V>();
    if (this.left != null) {
        values.addAll(this.left.getAllValues());
    }
    if (this.right != null) {
        values.addAll(this.right.getAllValues());
    }

    return values;
}
}
我注意到的是,如果我序列化到一个当前不存在的文件,它可以很好地序列化。第二次运行同一程序时,再次序列化到磁盘时,会导致StackOverflowException

以下是logcat的输出:

09-07 05:29:42.011: ERROR/AndroidRuntime(916): FATAL EXCEPTION: main 09-07 05:29:42.011: ERROR/AndroidRuntime(916): java.lang.StackOverflowError 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.util.IdentityHashMap.getModuloHash(IdentityHashMap.java:435) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.util.IdentityHashMap.findIndex(IdentityHashMap.java:419) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.util.IdentityHashMap.get(IdentityHashMap.java:371) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.dumpCycle(ObjectOutputStream.java:471) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1739) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1205) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413) 09-07 05:29:42.011: ERROR/AndroidRuntime(916): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.j
这通常发生在递归没有正确的退出条件时

我要复制你的错误。Android似乎不能很好地处理深度递归,因为我在桌面上尝试了相同的程序,并且它与我正在尝试的大小配合得很好

根据评论中的讨论,我做了不涉及对象级递归的替代序列化。实现这一点的方法肯定不止一种,但我选择将结构序列化为JSON数据格式的字符串,并将其写入输出流。请注意,我没有彻底测试它。这个答案的目的是提供一种您可能也可以采用的方法

现在假设我的值是int,我认为JSON结构应该如下所示:

{ root : { "value" : 8 "left": { "value" : 3 "left" : { "value" : 1 } }, "right" : { "value" : 10 "right" : { "value": 14 } } } } 相反地,要读回它:


private void readJSONObject(String json) throws JSONException, IllegalAccessException, InstantiationException {
        JSONObject baseJSON = new JSONObject(json);
        JSONObject rootElement = baseJSON.getJSONObject("root");
        readJSONObject(this, rootElement);
    }

    private void readJSONObject(BTree btree, JSONObject jsonElement) throws JSONException, IllegalAccessException, InstantiationException {
        int nodeValue = jsonElement.getInt("value");
        btree.value.setKey(nodeValue);

        if(jsonElement.has("left")) {
            JSONObject leftJSON = jsonElement.getJSONObject("left");
            Model m = this.value.getClass().newInstance();
            this.left = new BTree((V) m); 
            readJSONObject(this.left, leftJSON);
        } 

        if (jsonElement.has("right")){
            JSONObject rightJSON = jsonElement.getJSONObject("right");
            V m = (V)this.value.getClass().newInstance();
            this.right = new BTree(m); 
            readJSONObject(this.right, rightJSON);
        }
    }
最后,我应用自定义序列化:


 private void writeObject(ObjectOutputStream oos)
    throws IOException {
        try {
            oos.defaultWriteObject();
            JSONObject root = buildJSONObject(this);
            oos.writeObject(root.toString());
            oos.writeObject(this.value);
        } catch(Exception e) {
            // handle exception
            throw new RuntimeException(e);
        }
    }

    // assumes "static java.util.Date aDate;" declared
    private void readObject(ObjectInputStream ois)
    throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        String jsonString = (String)ois.readObject();
        this.value = (V)ois.readObject();

        try {
            readJSONObject(jsonString);
        } catch (Exception e) {
            // handle exception
            throw new RuntimeException(e);
        }
    }

下面是解决StackOverflowException问题的修订类的代码。它确实有一个关键缺点:对于不平衡的树,它的效率非常低,因为它必须反复调整内部数组的大小

class BTree<V extends Model> implements Serializable {  
/**
 * 
 */
private static final long serialVersionUID = -7602392759811243945L;

private static final int MINIMUM_CAPACITY = 15;

private Model[] values;
private int depth = 3;

public void insert(V newValue) {    
    int index = 0;
    while(true) {           
        ensureSpotExists(index);

        Model value = values[index];
        if (value == null) {                
            values[index] = newValue;
            return;
        } else if (newValue.getKey().hashCode() < value.getKey().hashCode()) {
            index = (2 * index) + 1;
        } else if (newValue.getKey().hashCode() > value.getKey().hashCode()) {
            index = (2 * index) + 2;
        } else {
            values[index] = newValue;
            return;
        }
    }
}

protected void ensureSpotExists(int index) {
    if (this.values == null) {
        this.values = new Model[MINIMUM_CAPACITY];
    } else if (this.values.length < index + 1) {
        Model[] temp = this.values;
        this.values = new Model[getSize(++depth)];
        for(int i = 0; i < temp.length; i++) {
            this.values[i] = temp[i];
        }
    }
}

protected static int getSize(int depth) {
    int size = 0;
    for(int i = 0; i <= depth; i++) {
        size += Math.pow(2, i);
    }

    return size;
}

public boolean containsKey(Object key) {
    return this.find(key) != null;
}

public V find(Object key) {
    return null;
}

void replace(Object key, V value) {
    return;
}

public List<Model> getAllValues() {
    return Arrays.asList(this.values);
}  
}

读完标题后,我认为这与网站有关P@Corey你能包括建立树的代码吗?似乎可以通过使用insert方法插入相同的节点来实现循环引用/constructor@mom-我已添加了我能找到的所有正在调用的代码行。请检查您的程序是否在任何数量的节点上失败,或者是否在较小数量的节点上工作,以及在大量节点上是否失败。在前一种情况下,肯定有一些循环引用正在消耗堆栈内存。@Santosh-它似乎确实适用于16个节点以下的情况。虽然我没有考虑过循环引用,但我会进一步调查。不幸的是,这也不起作用。它在同一点上给出了stackoverflow错误。不过还是不错的尝试。我对工作抱有希望。我确实让它与一个基于数组的BTree一起工作,我将很快在这里发布…或者树太深,也称为链表。序列化链表也可以做同样的事情 { root : { "value" : 8 "left": { "value" : 3 "left" : { "value" : 1 } }, "right" : { "value" : 10 "right" : { "value": 14 } } } }

    private JSONObject buildJSONObject(BTree  root) throws JSONException {
        JSONObject baseJSON = new JSONObject();
        JSONObject rootElement = new JSONObject();
        rootElement.put("value", root.getValue());
        baseJSON.put("root", rootElement);
        buildJSONObject(root, rootElement);
        return baseJSON;
    }

    private void buildJSONObject(BTree currentNode, JSONObject jsonElement) throws JSONException {
        jsonElement.put("value", currentNode.getValue());

        if(currentNode.left != null) {
            JSONObject leftJSON = new JSONObject();
            jsonElement.put("left", leftJSON);
            leftJSON.put("value", currentNode.left.getValue());
            buildJSONObject(currentNode.left, leftJSON);
        } 

        if (currentNode.right != null ){
            JSONObject rightJSON = new JSONObject();
            jsonElement.put("right", rightJSON);
            rightJSON.put("value", currentNode.right.getValue());
            buildJSONObject(currentNode.right, rightJSON);
        }
    }

private void readJSONObject(String json) throws JSONException, IllegalAccessException, InstantiationException {
        JSONObject baseJSON = new JSONObject(json);
        JSONObject rootElement = baseJSON.getJSONObject("root");
        readJSONObject(this, rootElement);
    }

    private void readJSONObject(BTree btree, JSONObject jsonElement) throws JSONException, IllegalAccessException, InstantiationException {
        int nodeValue = jsonElement.getInt("value");
        btree.value.setKey(nodeValue);

        if(jsonElement.has("left")) {
            JSONObject leftJSON = jsonElement.getJSONObject("left");
            Model m = this.value.getClass().newInstance();
            this.left = new BTree((V) m); 
            readJSONObject(this.left, leftJSON);
        } 

        if (jsonElement.has("right")){
            JSONObject rightJSON = jsonElement.getJSONObject("right");
            V m = (V)this.value.getClass().newInstance();
            this.right = new BTree(m); 
            readJSONObject(this.right, rightJSON);
        }
    }

 private void writeObject(ObjectOutputStream oos)
    throws IOException {
        try {
            oos.defaultWriteObject();
            JSONObject root = buildJSONObject(this);
            oos.writeObject(root.toString());
            oos.writeObject(this.value);
        } catch(Exception e) {
            // handle exception
            throw new RuntimeException(e);
        }
    }

    // assumes "static java.util.Date aDate;" declared
    private void readObject(ObjectInputStream ois)
    throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        String jsonString = (String)ois.readObject();
        this.value = (V)ois.readObject();

        try {
            readJSONObject(jsonString);
        } catch (Exception e) {
            // handle exception
            throw new RuntimeException(e);
        }
    }
class BTree<V extends Model> implements Serializable {  
/**
 * 
 */
private static final long serialVersionUID = -7602392759811243945L;

private static final int MINIMUM_CAPACITY = 15;

private Model[] values;
private int depth = 3;

public void insert(V newValue) {    
    int index = 0;
    while(true) {           
        ensureSpotExists(index);

        Model value = values[index];
        if (value == null) {                
            values[index] = newValue;
            return;
        } else if (newValue.getKey().hashCode() < value.getKey().hashCode()) {
            index = (2 * index) + 1;
        } else if (newValue.getKey().hashCode() > value.getKey().hashCode()) {
            index = (2 * index) + 2;
        } else {
            values[index] = newValue;
            return;
        }
    }
}

protected void ensureSpotExists(int index) {
    if (this.values == null) {
        this.values = new Model[MINIMUM_CAPACITY];
    } else if (this.values.length < index + 1) {
        Model[] temp = this.values;
        this.values = new Model[getSize(++depth)];
        for(int i = 0; i < temp.length; i++) {
            this.values[i] = temp[i];
        }
    }
}

protected static int getSize(int depth) {
    int size = 0;
    for(int i = 0; i <= depth; i++) {
        size += Math.pow(2, i);
    }

    return size;
}

public boolean containsKey(Object key) {
    return this.find(key) != null;
}

public V find(Object key) {
    return null;
}

void replace(Object key, V value) {
    return;
}

public List<Model> getAllValues() {
    return Arrays.asList(this.values);
}  
}