使用二进制序列化加载菜单
loading menu with binary serialization
我在 java 中做海战游戏,我用 JMenubar 创建了一个菜单,我希望能够保存和加载游戏。
我创建了一个 class chargerActionListener 来实现 ActionListener
将它添加到我的菜单中的项目但它不起作用,这对我来说不是 return 错误,但不会加载 plateau 对象,我的加载函数是正确,我测试过。
package actionlistener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JFileChooser;
import Main.Plateau;
import interfaceGraphique.Fenetre;
import ioforme.IOPlateau;
public class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public Plateau plateau;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(fenetre);
if(retour==JFileChooser.APPROVE_OPTION){
try {
Plateau p = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setPlateau(p);
System.out.println(choix.getSelectedFile().getAbsolutePath());
fenetre.actualiserGrilleCible();
fenetre.actualiserMaGrille();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我很快写了这段代码,它工作得很好,但同样的问题。
我有三个按钮;一个是在控制台中保存、加载和显示人体对象,我可以放心保存。
例如 :我用 human ("jean", 10) 启动程序(在主函数中)
我保存。
我退出我的程序并改变
人类("jean"、50)
当我按下加载按钮时
我加载我之前保存的文件
然后我点击按钮在控制台中显示它会显示我
"Human [jean, 50]"
但我想要 "Human [jean, 10]"
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.swing.*;
public class Main {
public static class Human implements Serializable {
String name;
int age;
public Human(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String toString() {
return "Human [name=" + name + ", age=" + age + "]";
}
}
public static class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {
Human h = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setHuman(h);
System.out.println(choix.getSelectedFile().getAbsolutePath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static class SauvegarderActionListener implements ActionListener {
public Fenetre fenetre;
public SauvegarderActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showSaveDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {
IOPlateau.sauver(fenetre.getHuman(),choix.getSelectedFile().getAbsolutePath());
System.out.println(choix.getSelectedFile().getAbsolutePath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static class Fenetre extends JFrame {
private Human human;
Fenetre (Human human)
{
this.human = human;
this.setTitle("test");
this.setSize(1200,500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton save = new JButton ();
save.addActionListener(new SauvegarderActionListener(this));
JButton load = new JButton();
load.addActionListener(new ChargerActionListener(this));
JButton display = new JButton ();
JPanel panel = new JPanel (new GridLayout(1,3));
// Button for load and save !
panel.add(save);
panel.add(load);
panel.add(display);
this.setContentPane(panel);
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement)
{
System.out.println(human);
}
});
this.setVisible(true);
}
public void setHuman (Human human)
{
this.human = human;
}
public Human getHuman ()
{
return this.human;
}
}
public static class IOPlateau {
public static Human lire(String fileName) throws IOException {
Human h = null;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
try {
h = (Human) ois.readObject();
} catch (ClassNotFoundException cnfe) {
// erreur de lecture
} catch (EOFException eofe) {
//fin de fichier
}
ois.close();
return h;
}
public static void sauver(Human h, String fileName) throws IOException {
try {
// Recevoir le fichier
File f = new File(fileName);
// Créer un nouveau fichier
// Vérifier s'il n'existe pas
if (f.createNewFile())
System.out.println("File created");
else
System.out.println("File already exists");
}
catch (Exception e) {
System.err.println(e);
}
ObjectOutputStream oos;
oos = new ObjectOutputStream(new FileOutputStream(fileName));
oos.writeObject(h);
oos.close();
}
}
public static void main(String[] args) {
Human human = new Human ("Jean",11);
Fenetre fenetre = new Fenetre(human);
}
}
您是否正确地将 ChargerActionListener 添加到项目中:
.addActionListener(new ChargerActionListener(fenetre));
也尝试使用:
JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
int returnValue = jfc.showOpenDialog(null);
也许 'null' 作为 'showOpenDialog' 的参数会起作用。
(我不知道fenetre或plateau应该是什么)
也可能只是对话框打不开,实际上是调用了Listener。
请通过 运行 类似(在 'actionPerformed' 中)的方式检查:
System.out.println("Ok");
您的序列化代码工作正常。您的问题在于如何显示获得的结果。你这样做:
public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(human);
}
});
// ....
}
// ....
}
您的 System.out.println(human);
调用是指传递给构造函数的参数,而不是 class 的字段,因此该值永远不会改变。
如果您现在将代码更改为:
public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(getHuman());
}
});
// ....
}
// ....
}
由于getHuman()
returns实例字段所持有的值,human,你会看到结果是正确的,human字段的参考值实际上已经改变了。
您的问题出在与 display JButton
关联的 actionListener()
方法中。因为 class 成员 human
与 class Fenetre
的构造函数中的参数具有相同的名称,所以在构造函数代码中任何你想访问成员的地方(而不是参数)您需要使用 this
关键字对其进行限定。
方法actionListener()
的写法如下:
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(Fenetre.this.human);
}
});
您需要 Fenetre.this.human
,因为您正在创建一个匿名的内部 class 并且 human
是封闭 class.
的成员
如果您至少使用 Java 8,则可以将匿名的内部 class 替换为 lambda expression,因为接口 java.awt.event.ActionListener
是功能接口,即一个只包含一个抽象方法的接口。这是替换匿名内部 class.
的 lambda 表达式
display.addActionListener(e -> System.out.println(this.human));
如你所见,在lambda表达式中你只需要写this.human
就可以访问class Fenetre
.[=25的成员human
=]
我在 java 中做海战游戏,我用 JMenubar 创建了一个菜单,我希望能够保存和加载游戏。
我创建了一个 class chargerActionListener 来实现 ActionListener 将它添加到我的菜单中的项目但它不起作用,这对我来说不是 return 错误,但不会加载 plateau 对象,我的加载函数是正确,我测试过。
package actionlistener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JFileChooser;
import Main.Plateau;
import interfaceGraphique.Fenetre;
import ioforme.IOPlateau;
public class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public Plateau plateau;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(fenetre);
if(retour==JFileChooser.APPROVE_OPTION){
try {
Plateau p = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setPlateau(p);
System.out.println(choix.getSelectedFile().getAbsolutePath());
fenetre.actualiserGrilleCible();
fenetre.actualiserMaGrille();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我很快写了这段代码,它工作得很好,但同样的问题。 我有三个按钮;一个是在控制台中保存、加载和显示人体对象,我可以放心保存。 例如 :我用 human ("jean", 10) 启动程序(在主函数中) 我保存。 我退出我的程序并改变 人类("jean"、50) 当我按下加载按钮时 我加载我之前保存的文件 然后我点击按钮在控制台中显示它会显示我 "Human [jean, 50]" 但我想要 "Human [jean, 10]"
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.swing.*;
public class Main {
public static class Human implements Serializable {
String name;
int age;
public Human(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String toString() {
return "Human [name=" + name + ", age=" + age + "]";
}
}
public static class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {
Human h = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setHuman(h);
System.out.println(choix.getSelectedFile().getAbsolutePath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static class SauvegarderActionListener implements ActionListener {
public Fenetre fenetre;
public SauvegarderActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;
}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showSaveDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {
IOPlateau.sauver(fenetre.getHuman(),choix.getSelectedFile().getAbsolutePath());
System.out.println(choix.getSelectedFile().getAbsolutePath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static class Fenetre extends JFrame {
private Human human;
Fenetre (Human human)
{
this.human = human;
this.setTitle("test");
this.setSize(1200,500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton save = new JButton ();
save.addActionListener(new SauvegarderActionListener(this));
JButton load = new JButton();
load.addActionListener(new ChargerActionListener(this));
JButton display = new JButton ();
JPanel panel = new JPanel (new GridLayout(1,3));
// Button for load and save !
panel.add(save);
panel.add(load);
panel.add(display);
this.setContentPane(panel);
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement)
{
System.out.println(human);
}
});
this.setVisible(true);
}
public void setHuman (Human human)
{
this.human = human;
}
public Human getHuman ()
{
return this.human;
}
}
public static class IOPlateau {
public static Human lire(String fileName) throws IOException {
Human h = null;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
try {
h = (Human) ois.readObject();
} catch (ClassNotFoundException cnfe) {
// erreur de lecture
} catch (EOFException eofe) {
//fin de fichier
}
ois.close();
return h;
}
public static void sauver(Human h, String fileName) throws IOException {
try {
// Recevoir le fichier
File f = new File(fileName);
// Créer un nouveau fichier
// Vérifier s'il n'existe pas
if (f.createNewFile())
System.out.println("File created");
else
System.out.println("File already exists");
}
catch (Exception e) {
System.err.println(e);
}
ObjectOutputStream oos;
oos = new ObjectOutputStream(new FileOutputStream(fileName));
oos.writeObject(h);
oos.close();
}
}
public static void main(String[] args) {
Human human = new Human ("Jean",11);
Fenetre fenetre = new Fenetre(human);
}
}
您是否正确地将 ChargerActionListener 添加到项目中:
.addActionListener(new ChargerActionListener(fenetre));
也尝试使用:
JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
int returnValue = jfc.showOpenDialog(null);
也许 'null' 作为 'showOpenDialog' 的参数会起作用。 (我不知道fenetre或plateau应该是什么)
也可能只是对话框打不开,实际上是调用了Listener。
请通过 运行 类似(在 'actionPerformed' 中)的方式检查:
System.out.println("Ok");
您的序列化代码工作正常。您的问题在于如何显示获得的结果。你这样做:
public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(human);
}
});
// ....
}
// ....
}
您的 System.out.println(human);
调用是指传递给构造函数的参数,而不是 class 的字段,因此该值永远不会改变。
如果您现在将代码更改为:
public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(getHuman());
}
});
// ....
}
// ....
}
由于getHuman()
returns实例字段所持有的值,human,你会看到结果是正确的,human字段的参考值实际上已经改变了。
您的问题出在与 display JButton
关联的 actionListener()
方法中。因为 class 成员 human
与 class Fenetre
的构造函数中的参数具有相同的名称,所以在构造函数代码中任何你想访问成员的地方(而不是参数)您需要使用 this
关键字对其进行限定。
方法actionListener()
的写法如下:
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(Fenetre.this.human);
}
});
您需要 Fenetre.this.human
,因为您正在创建一个匿名的内部 class 并且 human
是封闭 class.
如果您至少使用 Java 8,则可以将匿名的内部 class 替换为 lambda expression,因为接口 java.awt.event.ActionListener
是功能接口,即一个只包含一个抽象方法的接口。这是替换匿名内部 class.
display.addActionListener(e -> System.out.println(this.human));
如你所见,在lambda表达式中你只需要写this.human
就可以访问class Fenetre
.[=25的成员human
=]