Я пытаюсь реализовать двоичное дерево для приложения Android и хочу иметь возможность сериализовать его в файл на устройстве.К сожалению, я получаю ошибки переполнения стека при попытке его сериализации.
Код:
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;
}
}
И я пытаюсь сериализовать этот блок текста в отдельный класс:
try {
FileOutputStream fos = this.context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this.tree);
oos.close();
//this.lastModified = getLastModified(FILE_NAME);
} catch (FileNotFoundException e) {
//File will get created, so this doesn't matter
} catch (IOException e) {
Log.d("BTreeModel Serialization Error", "Error serialization model.");
Log.e("Serialization error details", e.toString());
}
Что я заметил, так это то, что если я сериализуюсь в файл, который в данный момент не существует, он сериализуется нормально.Второй раз, когда я запускаю ту же программу, она вызывает 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
Из действия, которое добавляет узлы:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//TextView averageHashMapTime = (TextView)findViewById(R.id.averageHashCollectionTime);
//averageHashMapTime.setText("Just a moment");
//TextView averageBtreeTime = (TextView)findViewById(R.id.averageBTreeCollectionTime);
//averageBtreeTime.setText("working");
HashMapModelCollection<Integer, Content> hashCollection = new HashMapModelCollection<Integer, Content>(this);
long totalTicks = 0;
final int totalIterations = 16;
BTreeModelCollection<Integer, Content> btreeCollection = new BTreeModelCollection<Integer, Content>(this);
totalTicks = 0;
for(int i = 0; i < totalIterations; i++) {
Content test = new Content();
test.setText(String.valueOf(i));
Random r = new Random();
int key = r.nextInt();
Date start = new Date();
btreeCollection.put(key, test);
Date end = new Date();
totalTicks += end.getTime() - start.getTime();
}
Log.d("Finished", "btree length: " + String.valueOf(totalTicks / totalIterations));
Toast.makeText(this, "btree length: " + String.valueOf(totalTicks / totalIterations), Toast.LENGTH_LONG).show();
//averageBtreeTime.setText(String.valueOf(totalTicks / totalIterations));
}
Класс, который непосредственно обрабатывает объекты BTree:
public class BTreeModelCollection<K extends Serializable, V extends Model> implements IModelCollection<K, V>,
Serializable {
/**
*
*/
private static final long serialVersionUID = -3969909157515987705L;
private static final String FILE_NAME = "testCollection-5";
private BTree<V> tree;
private Context context;
public BTreeModelCollection(Context context) {
this.context = context;
}
@Override
public void clear() {
// TODO Auto-generated method stub
}
@Override
public boolean containsKey(Object key) {
return tree.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
// TODO Auto-generated method stub
return false;
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
// TODO Auto-generated method stub
return null;
}
@Override
public V get(Object key) {
return getTree().find(key);
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
@Override
public Set<K> keySet() {
// TODO Auto-generated method stub
return null;
}
@Override
public void put(K key, V value) {
value.setKey(key);
getTree();
if (this.tree != null) {
this.tree.insert(new BTree<V>(value));
} else {
this.tree = new BTree<V>(value);
}
serialize();
}
@Override
public V remove(Object key) {
// TODO Auto-generated method stub
return null;
}
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Collection<V> values() {
return getTree().getAllValues();
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
// TODO Auto-generated method stub
}
private BTree<V> getTree() {
if (this.tree == null) {
loadTree();
}
return tree;
}
@SuppressWarnings("unchecked")
private void loadTree() {
try {
FileInputStream fis = context.openFileInput(FILE_NAME);
ObjectInputStream ois = new ObjectInputStream(fis);
this.tree = (BTree<V>)ois.readObject();
ois.close();
} catch (FileNotFoundException e) {
this.tree = null;
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (IOException e) {
this.tree = null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void serialize() {
if (this.tree == null) {
Log.w("Serialization problem", "No collection to serialize to disk");
return;
}
try {
FileOutputStream fos = this.context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this.tree);
oos.close();
//this.lastModified = getLastModified(FILE_NAME);
} catch (FileNotFoundException e) {
//File will get created, so this doesn't matter
} catch (IOException e) {
Log.d("BTreeModel Serialization Error", "Error serialization model.");
Log.e("Serialization error details", e.toString());
}
}
}
И класс Model:
public abstract class Model implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5724152403115334006L;
private Serializable key;
void setKey(Serializable key) {
this.key = key;
}
Serializable getKey() {
return this.key;
}
}