Ajuda com serialização (Resolvido)

11 respostas
java
W

Olá, sou novo no fórum, gostaria que vocês me ajudassem com a serialização de um objeto. Tenho uma classe Char que tem atributos de um jogador de RPG, porém quando modifico o nome e carrego o objeto salvo com outro “nome” ele não carrega o atributo “nome” do objeto des-serializado, mas o que eu setei entre o salvamento e o carregamento.

public class Main {
    public static void main(String[] args) {
	    Char player = new Char("Will", 1, 100, 100, 40, 40);
		
	        player.save();
		
		player.setName("Bob");
		
		player.load(player);
		
		System.out.println(player.getName());
	    }
}

E a saída sempre dá “Bob” ao invés de Will. O que estou fazendo de errado?

E aqui está a classe Char:

import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Char implements Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
	private int level;
	private int hp;
	private int mp;
	private int atk;
	private int def;

public static long getSerialVersionID(){
	return serialVersionUID;
}

public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
public int getLevel() {
	return level;
}
public void setLevel(int level) {
	this.level = level;
}
public int getHp() {
	return hp;
}
public void setHp(int hp) {
	this.hp = hp;
}
public int getMp() {
	return mp;
}
public void setMp(int mp) {
	this.mp = mp;
}
public int getAtk() {
	return atk;
}
public void setAtk(int atk) {
	this.atk = atk;
}
public int getDef() {
	return def;
}
public void setDef(int def) {
	this.def = def;
}

public void save() {
	try {
		FileOutputStream fileOut = new FileOutputStream("C:\\JavaIO\\player.save");
		ObjectOutputStream objOut = new ObjectOutputStream(fileOut);
		objOut.writeObject(this);
		objOut.close();
		fileOut.close();
	} catch(IOException e) {
		System.out.println("Ocorreu um erro: " + e.getMessage());
	}
}

public void load(Char c) {
	try {
		FileInputStream fileIn = new FileInputStream("C:\\JavaIO\\player.save");
		ObjectInputStream objIn = new ObjectInputStream(fileIn);
		c = (Char)objIn.readObject();
		objIn.close();
		fileIn.close();
	} catch(IOException e) {
		System.out.println("Ocorreu um erro: " + e.getMessage());
	} catch(ClassNotFoundException e) {
		System.out.println("Ocorreu um erro: " + e.getMessage());
	}
}

public Char(String name, int level, int hp, int mp, int atk, int def) {
	this.name = name;
	this.level = level;
	this.hp = hp;
	this.mp = mp;
	this.atk = atk;
	this.def = def;
}

}

E mais uma coisa: devo criar uma classe separada para os métodos save() e load() e assim poder salvar qualquer coisa, o estado do jogador, o inventário etc…?

11 Respostas

T

Aparentimente você esta salvando os dados antes de altera-los. O que esta acontecendo, é que vc salva com o nome “Will”, altera para “Bob” mas não salva a alteração. Dai quando vc faz o carregamento dos dados, na verdade vc esta buscando os dados salvos do “Will”.

E sim! Para a pergunta dos metodos para salvar estados do jogo.
É uma boa pratica separa as classes por responsabilidade.

W

Obrigado Thiago, mas o problema é justamente esse: eu salvei o nome “Will”, carreguei e ele me mostra “Bob”! Por que ele me mostra “Bob” depois do carregamento do estado salvo em que o nome é “Will”?

T

O seu metodo de load() não retorna nada, é um metodo sem retorno.
Não esta buscando o player salvo, esta simplismente impriminido o mesmo
objeto player modificado.

T

Bom... Você esta salvando de maneira correta.

Já na leitura, você esta passando um objeto por parâmetro, e nesse objeto você atribui o conteúdo do arquivo, só que em java sempre é passado uma cópia no parâmetro, e nunca o endereço da variável em si para ela ser modificada, ou seja, o seu objeto c está com o arquivo carregado direitinho, só que você não esta atribuindo nada ao seu objeto player apesar dele ter sido o parâmetro do método load.

Você pode mudar o tipo de retorno para Char, e em um bloco finally retornar c, então fazer
player = player.load(player)
Isso deve funcionar. Um exemplo pratico sobre copia é esse, ai você entenderá melhor
public class Main
{
	
	int a = 2;
	public void modificarValor(int numero)//Essa variável "numero" pode ser chamado de "a" que não irá mudar nada também
	{
		numero = numero + 5;
		System.out.println("Valor dentro do método -> " + numero);
		
	}
	public static void main(String[] args)
	{
		Main main = new Main();
		main.modificarValor(main.a);
		System.out.println("Valor fora do método -> " + main.a);
	}
}
W

Obrigado pessoal, entendi, é melhor usar um retorno e atribuir ao objeto. Quando passei o objeto como argumento na verdade eu estava passando somente uma cópia do valor e não o objeto em si (a referência). Obrigado mesmo!

T

Exato, testa lá e nos conta se funcionou

W

Deu certo, porém o Eclipse ainda me dá um warning no bloco finally (finally block does not complete normally):

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

public abstract class Game {
	public static boolean save(Object object){
		try {
			String path = "C:\\JavaIO\\";
			String extension = ".save";
			path = path.concat(object.toString());
			path = path.concat(extension);
			
			FileOutputStream fileOut = new FileOutputStream(path);
			ObjectOutputStream objOut = new ObjectOutputStream(fileOut);			
			objOut.writeObject(object);
			objOut.close();
			fileOut.close();
			return true;
		} catch(IOException e) {
			System.out.println(e.getMessage());
			return false;
		}
	}
	
	public static Object load(Object object) {
		try {
			String path = "C:\\JavaIO\\";
			String extension = ".save";
			path = path.concat(object.toString());
			path = path.concat(extension);
			
			FileInputStream fileIn = new FileInputStream(path);
			ObjectInputStream objIn = new ObjectInputStream(fileIn);
			object = objIn.readObject();
			objIn.close();
			fileIn.close();
		} catch(IOException e) {
			System.out.println(e.getMessage());
		} catch(ClassNotFoundException e) {
			System.out.println(e.getMessage());
		} finally {
			return object;
		}
	}
}

public class Main {
	public static void main(String args[]) {
		
		Char player = new Char("Will", 2, 100, 100, 40, 40);
		
		Game.save(player);
		
		player.setName("Bob");
		
		player = (Char)Game.load(player);
		
		System.out.println(player.getName());
	}
}

E quanto ao caminho (path) do arquivo, estou fazendo de maneira correta? Existe alguma desvantagem ou algum problema em usar o object.toString() para montar o nome do arquivo?

T

Eu acho que não tem problema algum utilizar o toString()

Eu falei para por o return em um bloco finally, mas eu acho que não é a maneira correta de se fazer isso, se você tirar o finally e por o return fora do try deverá funcionar também

W

Retirei o bloco finally, tem como montar um caminho relativo para o arquivo de save?

T

Criará um arquivo chamado arquivo.txt no projeto ao invés de criar no C;/JavaIO como você estava fazendo

E

Como regra geral, nunca use return em um bloco finally.

Criado 23 de setembro de 2016
Ultima resposta 24 de set. de 2016
Respostas 11
Participantes 4