0

I have a class called Library that extends ArrayList. I did this because (I think) a true is-a relationship exists between the Library class and an ArrayList - a Library is simply a collection of books, plus a few methods.

One of those methods is load(), which deserializes a saved Library object. My question is: How do I make the deserialized object into the "active" instance of Library? I want to do something like this = load() in the constructor of the library, since load() returns a Library object. However, I get a compiler error cannot assign a value to final variable this when I try to do it. What is the proper syntax to use for this purpose?

public class Library extends ArrayList<Book> implements Serializable{

public Library(){
    load();
}
...

Library load() throws IOException, ClassNotFoundException {
    File f = new File (System.getProperty("user.home")+"\\Documents\\CardCat\\library.ser");   
    ObjectInputStream ois = new ObjectInputStream (new FileInputStream (f));   
    Library lib = (Library)ois.readObject();
    System.out.println("ran load sucessfully");
    return lib;
}

EDIT: It seems that the universal consensus is that this is the wrong approach, and that I should instead create a Library class that doesn't extend ArrayList, but has an ArrayList instance variable. This is actually how I had it structured about an hour ago, but I thought that extending ArrayList might be a little simpler. My primary rationale for this was that the ArrayList was the only variable of the Library class, I refer to that ArrayList very frequently from other classes, and every time I did so I was having to call library.libList, so I thought being able to refer simply to library would be simpler. Looking back, and taking your input into consideration, it seems this this is a rather trivial benefit and it comes at the cost of a significant hit to performance.

Although I'd like to better understand what those costs are, am I understanding your thoughts correctly? I am (obviously, I'm sure) still learning and experimenting with all sorts of things, and very much appreciate any input that helps me identify failed experiments.

drew moore
  • 31,565
  • 17
  • 75
  • 112

4 Answers4

2

You can't overwrite this by design.

Some things to consider:

  • Why is a Library an ArrayList? Is there any case where you need your Library to be assignable to an ArrayList? Is there any reason that a Library must be a List and backed by an array? Implementing Collection may be reasonable, but forces you to implement methods that might not make sense in your design.
  • If a Library isn't an ArrayList, then you can use composition, which is easier to use anyway. Just have a member variable which is an ArrayList (or any kind of collection).
  • For deserialization, you usually use a static function or a factory, not the constructor. See other answers for how to do this.

To clarify my comments below with code, here's an example of adding the books as an instance variable, then creating whatever methods are necessary to access them from the outside:

class Library {
    private final Collection<Book> books = new ArrayList<Book>();

    public void addBook(Book book) {
        this.books.add(book);
    }

    public Collection<Book> getAllBooks() {
        ...
    }

    public Book getBookByTitle(String title) {
        ...
    }
}
Community
  • 1
  • 1
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • Deleting my answer in favor of this one. 1+ – Hovercraft Full Of Eels Mar 04 '13 at 23:47
  • 1
    @drewmore4 First off, stop worrying about performance. There won't be a significant difference and it's not even clear to me if inheritance will be faster than composition. To fix your design, make your ArrayList a private variable and create Library methods to do what you want. Users of your class shouldn't even know that there's an ArrayList inside of it. If your Library doesn't do anything except talk to the ArrayList, I'd advise not having a Library class at all (just use the ArrayList). – Brendan Long Mar 05 '13 at 00:25
1

You should do the loading instead of making a new instance of Library.

ddmps
  • 4,350
  • 1
  • 19
  • 34
1

The right way to do this is to make load a static method thar returns a brand new instance:

class Library {
  static Library load(Stream in) 
}
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
1

You could just do this:

public Library(){
    addAll(load());
}

As others have said, it isn't the best design practice to do this but perhaps you're doing something we don't know.

CodeBlind
  • 4,519
  • 1
  • 24
  • 36