我正在使用android / java
中Location的子类序列化位置不可序列化。 我有一个名为FALocation的第一个子类,它没有任何实例变量。我已宣布它可序列化。
然后我有一个名为Waypoint的第二个类看起来像这样:
public class Waypoint extends FALocation implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/* Class variables *******************************************************/
private static int CLASS_VERSION=1; //Used to version parcels
/* Instance variables ****************************************************/
private transient String type=DataHelper.PT_TYPE_US;
private transient String country;
private transient String name=null;
private transient String description=null;
private transient int elevation = 0;
private transient int population = 0; // Afterthought, added to match the DB structure
/* Constructors **********************************************************/
public Waypoint() {
super();
}
public Waypoint(double lat, double lon, String name, String description) {
super(lat, lon);
this.setName(name);
this.setDescription(description);
}
public Waypoint(Location l) {
super(l);
}
public Waypoint(String provider) {
super(provider);
}
/* Implementing serializable */
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
Log.v("DroidFA", "Serialising \"%s\" (v%d).", Waypoint.class.getSimpleName(), CLASS_VERSION);
out.writeInt(CLASS_VERSION);
out.writeObject(type);
out.writeObject(country);
out.writeObject(name);
out.writeObject(description);
out.writeInt(elevation);
out.writeInt(population);
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
int serialClassVersion = in.readInt();
Log.v("DroidFA", "Deserialising \"%s\" (v%d).", Waypoint.class.getSimpleName(),serialClassVersion);
type = (String) in.readObject();
country = (String) in.readObject();
name = (String) in.readObject();
description = (String) in.readObject();
elevation = in.readInt();
population = in.readInt();
}
}
序列化工作正常。
Deseriamization产生跟随异常(leg对象包含一个航点)。:
10-05 13:50:35.259: WARN/System.err(7867): java.io.InvalidClassException: android.location.Location; IllegalAccessException
10-05 13:50:35.267: WARN/System.err(7867): at java.io.ObjectInputStream.resolveConstructorClass(ObjectInputStream.java:2010)
10-05 13:50:35.267: WARN/System.err(7867): at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2095)
10-05 13:50:35.267: WARN/System.err(7867): at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:929)
10-05 13:50:35.267: WARN/System.err(7867): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2285)
10-05 13:50:35.278: WARN/System.err(7867): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2240)
10-05 13:50:35.278: WARN/System.err(7867): at com.droidfa.navigation.Leg.readObject(Leg.java:262)
.../...
答案 0 :(得分:11)
是否绝对有必要序列化位置?也许你可以将它标记为瞬态,并在反序列化对象后动态获取它。 (Anyway, from the documentation ):
问:如果A类没有实现Serializable但是子类B实现了Serializable,那么当B被序列化时,A类的字段会被序列化吗?
答:只写出并恢复Serializable对象的字段。仅当对象具有将初始化非可序列化超类型字段的无参数构造函数时,才可以恢复该对象。如果子类可以访问超类的状态,它可以实现writeObject和readObject来保存和恢复该状态。
因此,如果子类可以访问其非可序列化超类的字段,则可以使用writeObject和readObject协议来实现序列化。否则,将存在无法序列化的字段。
答案 1 :(得分:1)
看起来Location没有public / protected no-arg构造函数。需要这样的构造函数才能使其可用于子类中的序列化。
http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html说:
要允许序列化非序列化类的子类型, 子类型可能承担保存和恢复状态的责任 超类型的公共,受保护和(如果可访问)包 领域。只有在类中,子类型才可以承担此责任 它扩展了一个可访问的无参数构造函数来初始化 阶级的国家。如果这样,声明一个Serializable类是错误的 事实并非如此。将在运行时检测到错误。
与序列化规范中的词语相同:
Serializable类必须执行以下操作:...可以访问 no-arg构造函数的第一个非可序列化的超类
这可以解释为什么只在反序列化时遇到问题,因为在序列化过程中不会调用构造函数。
没有可访问构造函数的失败的小例子:
public class A {
public A(String some) {};
private A() {} //as protected or public everything would work
}
public class B extends A implements Serializable {
public B() {
super("");
}
//these doesn't really matter
//private void writeObject(java.io.ObjectOutputStream out) throws IOException { }
//private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { }
}
public class BSerializer {
public static void main(String ... args) throws Exception {
B b = new B();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(b);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
B deserialized = (B) ois.readObject(); //InvalidClassException
}
}