How to deserialize object from constructor in Java? - java

I am trying to do some funky stuff which i have never done before.
So what i am trying to do is:
I create an object by doing the following
Player playerVar = new Player(1234);
Players constructor will then look for a player called 1234, if it exists, it will then deserialize and store the loaded object under 'playerVar', if not it'll just follow through and give a'blank'` player object.
I am not sure if its even possible to make the current object an other instance of the same object, so i am posting here.
This is essentially what i am trying to do.
this = deserielizedObject
I know this can all be done by loading the object, then setting all the necessary variables manually, but that is hardly ideal. How can i 'replace' an object with another instance of itself, from within itself
This is the code i currently have
player.java
public class Player implements java.io.Serializable
{
Player(String GUID) // when loading a new player
{
Player player = loadPlayer(GUID);
//i want to set this to player
// something like this = player If you know what i mean....
}
Player()//when creating a new player
{
}
private Player loadPlayer(String GUID)
{
File f = new File("data/players/"+GUID+".ser");
if(!f.exists())
{
Player player = new Player();
return player;
}
Player player = null;
try
{
FileInputStream fileIn = new FileInputStream("data/players/"+GUID+".ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
player = (Player) in.readObject();
in.close();
fileIn.close();
}
catch(IOException i)
{
i.printStackTrace();
return null;
}
catch(ClassNotFoundException c)
{
System.out.println("Cant find Player Class!");
c.printStackTrace();
return null;
}
return player;
}
private int guid;
private String name;
private int bankMoney;
.......
...
.
}

You could use a factory class/method. The simpliest way in your case would probably be to just have loadPlayer as a public static method.
public static Player loadPlayer(String GUID)
{
...
return player;
}
then:
Player playerVar = Player.loadPlayer(1234);

What you describe is not possible. But you could create a (static) factory method instead of the constructor, which either deserializes or creates a new instance.

You cannot assign a value to this, not possible. Why not directly call the loadPlayer method:
Player player = Player.loadPlayer(GUID); //having loadPlayer as public static

Related

How to save and load a class that contains a list of another class?

I had a class Inventory that contains a list of Treasure class. I designed the Reader to read the Inventory as a list of Treasure, but when I want to call the reader from my main function, it says that Inventory is not the same as a list of Treasure. And now I don't know what should I do, should I change the read method to only read Inventory, but then again Inventory contains all the list of Treasure that I need. I am very lost as how to do it.
public class Inventory implements SavedGames {
private ArrayList<Treasure> inventory;
private static Inventory instance;
// EFFECTS: constructs an empty player inventory
private Inventory() {
this.inventory = new ArrayList<Treasure>();
inventory.add(new Treasure("Potion", 4));
}
private void loadGames() {
try {
MainCharacter character = Reader.readCharacter(new File(CHARACTER_FILE));
Monster monster = Reader.readMonster(new File(MONSTER_FILE));
List<Treasure> inventory = Reader.readInventory(new File(INVENTORY_FILE));
this.character = character;
this.monster = monster;
this.inventory = inventory;
} catch (IOException e) {
System.out.println("Unable to read files, resetting...");
startApp();
}
}
private static List<Treasure> parseInventory(List<String> fileContent) {
List<Treasure> inventory = new ArrayList<>();
for (String line : fileContent) {
ArrayList<String> lineComponents = splitString(line);
inventory.add(parseTreasure(lineComponents));
}
return inventory;
}
private static Treasure parseTreasure(List<String> components) {
String description = components.get(0);
int amount = Integer.parseInt(components.get(1));
return new Treasure(description, amount);
}
}
Serialization is a mechanism of converting the state of an object into a byte stream. Deserialization is the reverse process where the byte stream is used to recreate the actual Java object in memory. This mechanism is used to persist the object.
The byte stream created is platform independent. So, the object serialized on one platform can be deserialized on a different platform.
To make a Java object serializable we implement the java.io.Serializable interface.
The ObjectOutputStream class contains writeObject() method for serializing an Object.
public final void writeObject(Object obj)
throws IOException
The ObjectInputStream class contains readObject() method for deserializing an object.
public final Object readObject()
throws IOException,
ClassNotFoundException

Java : How to create an object in a method and use it throughout the class?

public void setupPlayers() {
System.out.println("Would you like the Code Maker to be Human or CPU? :");
String input = mySc.next();
if (input == "Human") {
Player CodeMaker = new Human();
}
else {
Player CodeMaker = new CPU();
}
public void exampleUse() {
CodeMaker.getCode();
}
So I'm new to Java and not even sure if this is possible to begin with. The above code is all inside one class. Human is implementing the interface Player. I want to create an object CodeMaker using the class Human in the method setupPlayers, and then use this object in the method exampleUse. Is there a way to do this? If not can anyone think of any alternatives? Cheers.
I think that you must mean the Player is the interface. And remember that if you want to compare the String, you should use equals method instead of == operator.
public class ClassName{
private Player codeMaker;
public void setupPlayers() {
System.out.println("Would you like the Code Maker to be Human or CPU? :");
String input = mySc.next();
if (input.equals("Human")) {
codeMaker = new Human();
}
else {
codeMaker = new CPU();
}
}
public void exampleUse() {
codeMaker.getCode();
}
}
You may store the Player object as an instance variable :
Player CodeMaker = null;
public void setupPlayers() {
System.out.println("Would you like the Code Maker to be Human or CPU? :");
String input = mySc.next();
if (input == "Human") {
CodeMaker = new Human();
}
else {
CodeMaker = new CPU();
}
}
public void exampleUse() {
CodeMaker.getCode();
}
Create a class field variable (private, for good encapsulation) and use "string".equals(object) to check string equality (How do I compare strings in Java?).
private Player codeMaker;
public void setupPlayers() {
System.out.println("Would you like the Code Maker to be Human or CPU? :");
String input = mySc.next();
if ("Human".equals(input)) {
codeMaker = new Human();
}
else {
codeMaker = new CPU();
}
}
public void exampleUse() {
codeMaker.getCode(); // you need to define a return or consumption HERE
}
Maybe you should wrap input = mySc.next() in a try/catch like this, because input read can throw an Exception.
[...]
String input = null;
try {
input = mySc.next();
}
catch(Exception ex) {
throw ex;
}
if ("Human".equals(input) {
codeMaker = new Human();
}
[...]
Just create a member of class: private Human CodeMaker; and initialize it in constructor CodeMaker = new Player();
Don't do Player CodeMaker = new Human(); - this should give you an error because you can't create an object of interface.
Please, consider studying Creational Design Patterns. Java's culture is focused on organization and good architecture. You'll be certainly surprised with the world Design Patterns can give to you.

field goes out of scope java

I have some problem with multithreaded application. I want to load the data from a CSV like file and store it in a buffer for later retrieval.
Seems like the animals list goes out of scope when the thread is finished(?), there is something about java threading I don't understand and will be grateful for assistance.
The way it's invoked:
ParseCSV parser = new ParseCSV(null);
EventQueue.invokeLater(parser);
System.err.println("printing!");
EDIT - as requested, this is the part that fails - the content of praser buffer is empty at this point. I thought that if I use new keyword in the parser, the content of animals will be persistent.
while(parser.hasNext()){
System.err.println("#");
System.err.println(parser.getNext().toString());
}
The parser class:
public class ParseCSV implements Runnable{
private String path = null;
private File file = null;
private static Logger log = LogManager.getLogger(ParseCSV.class.getName());
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
private int pointer =0;
public ParseCSV(String path) {
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
if(path == null){
JFileChooser jfc = new JFileChooser();
jfc.showOpenDialog(null);
file = jfc.getSelectedFile();
this.path = file.getAbsolutePath();
}
else {
this.path = path;
}
log.debug("Initialized file parser for " + this.path);
}
#Override
public void run() {
log.debug("begining file parse");
System.err.println("runnner");
try {
Scanner fileScan = new Scanner(this.file);
while(fileScan.hasNextLine()){
parseLine(fileScan.nextLine());
}
fileScan.close();
} catch (FileNotFoundException e) {
log.error("Exception occured: " + e.getMessage() + "\nstack:\n" + e.getStackTrace());
System.err.println("Exception: " + e.getMessage());
e.printStackTrace();
}
}
private void parseLine(String nextLine) {
Scanner lineScanner = new Scanner(nextLine);
lineScanner.useDelimiter("\\s\\|\\s");
if(lineScanner.hasNext()){
Animal an = new Animal(lineScanner.next(), //person
lineScanner.next(), //animal
Integer.parseInt(lineScanner.next()), //emp-number
lineScanner.next(), //date
Integer.parseInt(lineScanner.next()), //ani-number
lineScanner.next());
animals.add(an); //contract ID
System.err.println(an.toString()); //prints correct result!
}
lineScanner.close();
}
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public boolean hasNext(){
System.err.println("size of data = " + animals.size());
if(animals.size() == pointer || animals.isEmpty()) return false;
else return true;
}
public Sale getNext(){
if(animals.size() == pointer) return null;
return animals.get(pointer++);
}
}
EDIT - added comments to point out where the problem appears
You need to wait for the Parser thread to finish (currently both are happening at same time) This may be the reason that your program is not printing anything.
you can try adding some logging statements and check if the sequence is proper on not.
EventQueue#invokeLater adds a task to the event queue, so it might not be done when coming to the next line.
Use EventQueue#invokeAndWait instead, it waits for the task to finish.
There are a few problems with your code. Some of them actually leads to the problem, and some just shows that you don't really understand what you are trying to do.
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
Why are you using volatile on this? Each thread have their own animals list, so they are just used by one thread. If your main class had a animals model that everyone added to, you would have needed to make it volatile, since multiple threads could access it.
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
This isn't going to change anything. It might be useful if you think the method could get called multiple times and you want a fresh list each time, but it's probably just a waste.
Now onto the real problem:
When you call a thread it's because you want it to run in the background and not stop the main program execution. Then you can get back to the result at some time when it's actually finished. As people have said, if you just want a new thread without it really running in the background you could do EventQueue#invokeAndWait, but for your case this isn't the solution.
You could use the observer pattern. To do this you make an interface that has a notify method (call it parseListner or something). The parser has a list of parseListerners. When the parser finish parsing it tells all the listeners (by calling a method on the interface). So you end up with code sort of like this:
public interface ParseListner{
void fileParsed(String fileName, List<Animal> animals);
}
public class Main implements ParseListner{
public void main(){
ParseCSV parser = new ParseCSV(this);
EventQueue.invokeLater(filePath, parser);
}
public void fileParsed(String fileName, List<Animal> animals){
System.Out.Println(doneParsing);
}
}
public class ParseCSV implements Runnable{
List listners = new ArrayList<>();
public ParseCSV(String path, ParseListner caller) {
listner.add(caller)
}
#Override
public void run() {
//all the parsestuff
for(ParseListner p : listners)
p.parsedFile(fileName, animals);
}
I used a list because it's almost always useful (so you can do multiple things when it's done).

Issue with IF Statement Java

I have created a boolean called multiplay.
private boolean multiplay;
within my public Game() I have:
// make a player
player = new Player(this);
if(multiplay == true) {
player2 = new Player(this);
}
Within the actually class file I have created a method:
public void startMutliPlayer() {
multiplay = true;
}
What I am trying to do is when startMultiPlayer is called it will set the boolean multiplay as true, therefore, two players will be added to the frame not one. if 'startMultiPlayer' is not called it will only add one player.
At the moment it only adds one player not two when I called startMultiPlayer.
UPDATE:
Was able to sort this issue out using the following code:
// Make Players (Single & MultiPlayer)
if (multiplay == false) {
player = new Player(this);
player.setPosition(startPosition);
player.move(new Vec2(-210, 0));
multiplay = true;
} else if(multiplay == true) {
player = new Player(this);
player.setPosition(startPosition);
player.move(new Vec2(-210, 0));player2 = new Player(this);
player2.setPosition(startPosition);
player2.move(new Vec2(-150, 0));
multiplay = false;
}
public static void startMutliPlayer() {
multiplay = false;
}
Thanks
Which object of the Game class are you calling startMultiPlay on? Since it will always be called after the Game constructor is called, it will not work - because when the Game ctor is called, multiplay will be false.
On way to fix this is
private boolean multiplay;
needs to be changed to
private static boolean multiplay;
Also make startMultiPlayer as static and call it before you create a Game object.
Another way is not to create Player's in Game's ctor.
Have to methods startMultiPlayer and startSinglePlayer - create one or two Player objects in these methods respectively.
Create a method in your Game class, i.e.
public void setMultiplay(boolean multiplay) {
this.multiplay = multiplay; // scope
if (multiplay) {
player2 = new Player(this);
}
}
I'm guessing you are calling the method startMultiPlayer() on an object of the class Game.
However, the constructor is the first thing to be executed when you create an object in Java.
Game game = new Game();
game.startMultiPlayer();
will execute the following lines in this order:
// make a player
player = new Player(this);
if(multiplay == true) {
player2 = new Player(this);
}
multiplay = true;
which means multiplay is set to true after you check if it's true. Therefore, you will still be in singleplayer mode.
Try checking if multiplay is true after calling (or not calling) the startMultiPlayer() method.
Also note that you can simply write if(multiplay) instead of if(multiplay==true) since if-statements in Java can only take booleans. But that's personal preference, this is probably optimized automatically anyway.

Saving arrays of custom class objects

I was wondering if there was an easy way to save arrays of objects, without having to go through and save each aspect of the the objects. In my example I have two arrays, one a single array and the other a 2D array, that contain objects referring to a custom class. Each object has specific details like x and y ints, booleans, strings, ect. attached to them (block[0].x, block[0].canWalk, block[0].name) and I was wondering if there is an easy way of saving these arrays to a file without having to use a for loop and save each part. The multidimensional array is simply an array of saved arrays identical to the first one (savedBlock[0][0].x ...)
What I have so far (throwing NotSerializableException):
public class Save
{
static File f;
static ObjectOutputStream os;
public static void openFile()
{
try
{
if(!new File("c:\\IDsGame").exists())
{
new File("c:\\IDsGame").mkdirs();
}
f = new File("c:\\IDsGame\\data.bin");
os = new ObjectOutputStream(new FileOutputStream(f));
writeFile();
}
catch(Exception e)
{
System.err.println("creating file");
}
}
public static void writeFile()
{
try
{
ArrayList<Object> map = new ArrayList<Object>(Arrays.asList(Map.block));
ArrayList<Object> savedMaps = new ArrayList<Object>(Arrays.asList(Map.savedMaps));
os.writeObject(map);
os.writeObject(savedMaps);
os.close();
}
catch (IOException e) {System.out.println(e);}
}
}
Within my map class I initialize block (Blocks[]) and savedMaps(Blocks[][]). My Blocks class holds this:
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public Image img = null, imgBack = null;
public final Image (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Obviously I change the certain parts different arrays within the Map class, and I was wondering if there was any easier way (at all) to save the arrays of Blocks Objects.
Thanks for taking your time to help and if you need any more specific just let me know.
I.D.
Image is not serializable, so you receive a NotSerializableException when the Blocks class is serialized. ImageIcon can be serialized, so wrapping Image instances in ImageIcons will solve that issue.
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public ImageIcon img = null, imgBack = null;
public final ImageIcon (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
// img = new ImageIcon(someImageInstance)
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Just making a class implement Serializable is not enough: All the fields must be Serializable too.
Your Block class may have a problem. All the usual java classes are Serializable, but Block also has fields of type Image. If Image isn't Serializable, then attempting to serialize Block will throw NotSerializableException.

Categories