"Hello, Amigo! Today we'll learn about another interesting topic. Specifically, saving and loading (reconstructing) objects. Suppose we have a Cat class:"
class Cat
{
public String name;
public int age;
public int weight;
}
And let's say we want to add a convenient mechanism for saving to and loading from a file.
We could do it like this:
class Cat {
public String name;
public int age;
public int weight;
public void save(PrintWriter writer) throws Exception {
writer.println(name);
writer.println(age);
writer.println(weight);
writer.flush();
}
public void load(BufferedReader reader) throws Exception {
name = reader.readLine();
age = Integer.parseInt(reader.readLine());
weight = Integer.parseInt(reader.readLine());
}
}
"Wow! That's so easy! We just write the values of each argument, one on each line. When we load the file, we read them in the same order. It's the perfect solution."
"Thanks, Amigo. Now you can write the save and load methods for this group of classes:"
class Cat
{
public String name;
public int age;
public int weight;
}
class Dog
{
public String name;
public int age;
}
class Human
{
public Cat cat;
public Dog dog;
}
You have an Human object, which can have one dog and one cat.
"I have a solution:"
class Cat {
public String name;
public int age;
public int weight;
public void save(PrintWriter writer) throws Exception {
writer.println(name);
writer.println(age);
writer.println(weight);
writer.flush();
}
public void load(BufferedReader reader) throws Exception {
name = reader.readLine();
age = Integer.parseInt(reader.readLine());
weight = Integer.parseInt(reader.readLine());
}
}
class Dog {
public String name;
public int age;
public void save(PrintWriter writer) throws Exception {
writer.println(name);
writer.println(age);
writer.flush();
}
public void load(BufferedReader reader) throws Exception {
name = reader.readLine();
age = Integer.parseInt(reader.readLine());
}
}
public class Human {
public Cat cat;
public Dog dog;
public void save(PrintWriter writer) throws Exception {
cat.save(writer);
dog.save(writer);
}
public void load(BufferedReader reader) throws Exception {
cat.load(reader);
dog.load(reader);
}
}
"That's a very good solution. But what happens if a human has a dog but no cat?"
Where are the null checks?
"I'll fix it now:"
public class Human {
public Cat cat;
public Dog dog;
public void save(PrintWriter writer) throws Exception {
if (cat != null)
cat.save(writer);
if (dog != null)
dog.save(writer);
}
public void load(BufferedReader reader) throws Exception {
cat = new Cat();
cat.load(reader);
dog = new Dog();
dog.load(reader);
}
}
"It's still not quite right. You have two errors:"
1) A person might not have a cat or dog, but they will still be created when the load method is called
2) If we only save a dog, its data will be read by the cat when it is loaded.
"Well, what should I do?"
"We can't skip writing the variables, otherwise we'll have problems during reading. You need to make sure that variables that are null during the save operation are set to null during the load operation. Here's my version:"
public class Human {
public Cat cat;
public Dog dog;
public void save(PrintWriter writer) throws Exception {
String isCatPresent = cat != null ? "yes" : "no";
writer.println(isCatPresent);
writer.flush();
if (cat != null)
cat.save(writer);
String isDogPresent = dog != null ? "yes" : "no";
writer.println(isDogPresent);
writer.flush();
if (dog != null)
dog.save(writer);
}
public void load(BufferedReader reader) throws Exception {
String isCatPresent = reader.readLine();
if (isCatPresent.equals("yes")) {
cat = new Cat();
cat.load(reader);
}
String isDogPresent = reader.readLine();
if (isDogPresent.equals("yes")) {
dog = new Dog();
dog.load(reader);
}
}
}
"Yes, I like this solution."
"Yeah, it's nice."
GO TO FULL VERSION