Javafx IO异常关于;实现“可序列化”;
我在javafx文件IO上遇到了一些问题。我已经实现了Serializable,但也有一些错误。谢谢你的帮助 1.Appdata类Javafx IO异常关于;实现“可序列化”;,java,eclipse,exception,serialization,javafx,Java,Eclipse,Exception,Serialization,Javafx,我在javafx文件IO上遇到了一些问题。我已经实现了Serializable,但也有一些错误。谢谢你的帮助 1.Appdata类 package data; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream;
package data;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import model.*;
public class AppData implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final ObservableList<Customer> cusInfo = FXCollections.observableArrayList();
static{
Customer Raven = new Customer();
Raven.setName(new SimpleStringProperty("Raven"));
Raven.setPassword("raven09");
Customer Messi = new Customer();
Messi.setName(new SimpleStringProperty("Messi"));
Messi.setPassword("messi10");
Customer Ronaldo = new Customer();
Ronaldo.setName(new SimpleStringProperty("Ronaldo"));
Ronaldo.setPassword("ronaldo07");
Customer Neymar = new Customer();
Neymar.setName(new SimpleStringProperty("Neymar"));
Neymar.setPassword("neymar11");
Account RavenFund = new Account();
RavenFund.setBalance("1000000");
RavenFund.setName(new SimpleStringProperty("RavenFund"));
RavenFund.setLimit("200000");
RavenFund.setType("private");
Account MeRo = new Account();
MeRo.setBalance("200000");
MeRo.setName(new SimpleStringProperty("MeRo"));
MeRo.setLimit("60000");
MeRo.setType("private");
Account Barcelona = new Account();
Barcelona.setBalance("40000");
Barcelona.setName(new SimpleStringProperty("Barcelona"));
Barcelona.setLimit("680000");
Barcelona.setType("business");
Account Madrid = new Account();
Madrid.setBalance("70651");
Madrid.setName(new SimpleStringProperty("Madrid"));
Madrid.setLimit("8000");
Madrid.setType("business");
Raven.add(RavenFund);
Raven.add(Barcelona);
Messi.add(MeRo);
Messi.add(Barcelona);
Ronaldo.add(MeRo);
Ronaldo.add(Madrid);
Neymar.add(Barcelona);
cusInfo.add(Raven);
cusInfo.add(Messi);
cusInfo.add(Ronaldo);
cusInfo.add(Neymar);
}
public static void writeObject() {
try {
FileOutputStream outStream = new FileOutputStream("appdata.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outStream);
objectOutputStream.writeObject(cusInfo);
outStream.close();
System.out.println("successful");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readObject(){
FileInputStream freader;
try {
freader = new FileInputStream("appdata.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(freader);
ObservableList<Customer> cusINFO =FXCollections.observableArrayList();
cusINFO = (ObservableList<Customer>) objectInputStream.readObject();
//System.out.println("The name is " + cusINFO.get("name"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.客户类别
package model;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
* @author Raven Xu
* @version 1.2
* @version 1.1
*
*/
public class Customer implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private StringProperty name;
private StringProperty password;
private ObservableList<Account> accounts;
public Customer() {
accounts = FXCollections.observableArrayList();
name = new SimpleStringProperty();
password = new SimpleStringProperty();
}
public StringProperty getName() {
return name;
}
public void setName(StringProperty name) {
this.name = name;
}
public String getPassword() {
return password.get();
}
public void setPassword(String password) {
this.password.set(password);
}
public void add(Account a) {
accounts.add(a);
}
public ObservableList<Account> getAccounts() {
return accounts;
}
}
5.错误信息
java.io.NotSerializableException: com.sun.javafx.collections.ObservableListWrapper
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at data.AppData.writeObject(AppData.java:74)
at view.Main.start(Main.java:13)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Unknown Source)
我的英语很好。如果您能帮助我,我真的非常感谢您。首先,您正在尝试将ObservableList传递给ObjectOutputStream.writeObject。如前所述,该ObservaleList是由FXCollections.ObservalArrayList()返回的,不能保证可序列化 即使该ObservableList是可序列化的,序列化它也会自动序列化其元素—客户实例,而客户实例本身也会有序列化问题。Customer的非静态字段是SimpleStringProperty实例,它们是,并且从另一个对FXCollections.observableArrayList()的调用中获得的ObservableList(我们已经建立)不保证是可序列化的 作为类的作者,如果您使类实现可序列化,那么您有责任确保其字段可以序列化。当然,一种方法是确保每个字段的类型都是可序列化的类型。但由于您使用的是JavaFX属性,所以这不是一个选项。这意味着您必须自己处理序列化。幸运的是,这一过程在以下章节中描述得相当好: 在序列化和反序列化过程中需要特殊处理的类必须使用以下精确签名实现特殊方法:
私有void writeObject(java.io.ObjectOutputStream out)
抛出IOException
private void readObject(java.io.ObjectInputStream-in)
抛出IOException,ClassNotFoundException
writeObject方法负责为其特定类写入对象的状态,以便相应的readObject方法可以还原它。保存对象字段的默认机制可以通过调用out.defaultWriteObject来调用。该方法不需要关心属于其超类或子类的状态。通过使用writeObject方法或使用DataOutput支持的基本数据类型的方法将各个字段写入ObjectOutputStream来保存状态
readObject方法负责从流中读取并恢复类字段。它可以调用in.defaultReadObject来调用用于恢复对象的非静态和非瞬态字段的默认机制。defaultReadObject方法使用流中的信息将保存在流中的对象的字段与当前对象中相应命名的字段一起分配。这将处理类进化为添加新字段的情况。该方法不需要关心属于其超类或子类的状态。通过使用writeObject方法或使用DataOutput支持的基本数据类型的方法将各个字段写入ObjectOutputStream来保存状态
这意味着您的类需要添加一个writeObject
方法来进行自己的序列化,写入已知可序列化类型的对象:
public class Customer
implements Serializable {
private static final long serialVersionUID = 1;
private transient StringProperty name;
private transient StringProperty password;
private transient ObservableList<Account> accounts;
// ...
/**
* Performs custom serialization of this instance.
* Automatically invoked by Java when this instance is serialized.
*
* @param out stream to write this object to
*
* @throws IOException if any error occurs while writing
*
* @serialData String representing {@link #name};
* String representing {@link #password};
* Account[] array representing {@link #accounts}
*
* @see #readObject(ObjectInputStream)
*/
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject(); // always call this first
out.writeObject(name.get());
out.writeObject(password.get());
out.writeObject(accounts.toArray(new Account[0]));
}
/**
* Performs custom deserialization of transient fields.
* Automatically invoked by Java during deserialization.
*
* @param in stream from which this object is being read
*
* @throws IOException if any error occurs while reading
* @throws ClassNotFoundException if any object is read which belongs to an unknown class
*
* @see #writeObject(ObjectOutputStream)
*/
private void readObject(ObjectInputStream in)
throws IOException,
ClassNotFoundException {
in.defaultReadObject(); // always call this first
name = new SimpleStringProperty((String) in.readObject());
password = new SimpleStringProperty((String) in.readObject());
accounts = FXCollections.observableArrayList((Account[]) in.readObject());
}
(是否确实要将余额存储为字符串而不是(例如)a?)
我还应该指出,Customer和Account的getName
和setName
方法都不符合javafxbean。如果查看任何JavaFX类,例如,您将看到每个可写(相对于只读)属性都有三个方法。例如,考虑<代码>标题>代码>阶段属性:
public StringProperty titleProperty();
public String getTitle();
public void setTitle(String newTitle);
如您所见,标准JavaFX约定是使StringProperty对象本身不可更改,同时使StringProperty包含的值可修改。get/set方法使用String,但从不使用StringProperty
*从技术上讲,在某些情况下,反序列化可以调用构造函数,但这些情况不适用于实现或继承可序列化接口的任何类。FXCollections.ObservalArrayList()的返回值不可序列化!我将列表更改为Hashmap。这也是我第三次问关于堆栈溢出的问题。我非常感谢你能给我这么好的回答!非常感谢,我学到了很多。非常感谢。对不起,我想问一下什么时候我应该调用writeObject方法和readObject方法?(我学Java才一个多月,hh)你不应该调用它们。它们是由Java的序列化机制自动检测和调用的特殊方法名。有关此操作的完整说明,请参阅。
public class Customer
implements Serializable {
private static final long serialVersionUID = 1;
private transient StringProperty name;
private transient StringProperty password;
private transient ObservableList<Account> accounts;
// ...
/**
* Performs custom serialization of this instance.
* Automatically invoked by Java when this instance is serialized.
*
* @param out stream to write this object to
*
* @throws IOException if any error occurs while writing
*
* @serialData String representing {@link #name};
* String representing {@link #password};
* Account[] array representing {@link #accounts}
*
* @see #readObject(ObjectInputStream)
*/
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject(); // always call this first
out.writeObject(name.get());
out.writeObject(password.get());
out.writeObject(accounts.toArray(new Account[0]));
}
/**
* Performs custom deserialization of transient fields.
* Automatically invoked by Java during deserialization.
*
* @param in stream from which this object is being read
*
* @throws IOException if any error occurs while reading
* @throws ClassNotFoundException if any object is read which belongs to an unknown class
*
* @see #writeObject(ObjectOutputStream)
*/
private void readObject(ObjectInputStream in)
throws IOException,
ClassNotFoundException {
in.defaultReadObject(); // always call this first
name = new SimpleStringProperty((String) in.readObject());
password = new SimpleStringProperty((String) in.readObject());
accounts = FXCollections.observableArrayList((Account[]) in.readObject());
}
public class Account
implements Serializable {
private static final long serialVersionUID = 1;
private transient StringProperty name;
private transient StringProperty type;
private transient StringProperty limit;
private transient StringProperty balance;
// ...
/**
* [javadoc omitted; should be similar to javadoc of Customer.writeObject]
*
* @serialData String representation of {@link #name};
* String representation of {@link #type};
* String representation of {@link #limit};
* String representation of {@link #balance}
*/
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject(); // always call this first
out.writeObject(name.get());
out.writeObject(type.get());
out.writeObject(limit.get());
out.writeObject(balance.get());
}
/**
* [javadoc omitted; should be similar to javadoc of Customer.readObject]
*/
private void readObject(ObjectInputStream in)
throws IOException,
ClassNotFoundException {
in.defaultReadObject(); // always call this first
name = new SimpleStringProperty((String) in.readObject());
type = new SimpleStringProperty((String) in.readObject());
limit = new SimpleStringProperty((String) in.readObject());
balance = new SimpleStringProperty((String) in.readObject());
}
public StringProperty titleProperty();
public String getTitle();
public void setTitle(String newTitle);