• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Initialization hook for subclasses - a void init() method.

 
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Currently I'm going through the source code of java.util.HashMap class. There is this method in the source of HashMap class that I can't understand.



I have not understood why readObject would require explicit knowledge of subclasses if this method wasn't there and how it prevents that dependency.
It's not like I've just posted this question without doing a google search. I did the search and came across this post.

http://stackoverflow.com/questions/7477553/in-java-is-there-a-legitimate-reason-to-call-a-non-final-method-from-a-class-co

Sorry but I still haven't understood much.

I'm quite sure that this is a good coding style and it must address some subtle aspect about the readObject method but I can't figure how and what. Could you please help me.

Thanks,
Chan.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, so someone has posted this in the same thread.

This is interesting. It seems it's necessary because of the constructor where you provide an existing Map and the constructor will add the entries from the existing map - init() must be called before adding any entries. At least they made the method package-private so they have some control over it. I can see LinkedHashMap overrides it to initialize the linked list header, as an example. – Kevin K Sep 19 '11 at 22:24



While I have understood this, I do not understand the dependency of this method with the readObject method. I understand it is package private so that immutability cannot be compromised upon to a certain extent ( or would that be wrong? ). But still, why is the method required, remains a puzzle to me.

And why should it be called if 'the constructor will add the entries from the existing map'. I see it is called by other constructors too.

Am I missing something here?
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just wanted to tell you all that although I've posted this question here, it doesn't mean I'm not working on finding its answer of my own. So if you feel that you could pass on a hint or two, I'd appreciate it.

I'm going through how clone and readObject work; if I come across anything, I shall post it or shall ask you all to confirm if my understanding is correct.

Regardless, hints are always nice things to have.

By the way, if you feel I'm wasting time working on this thing, let me know that also. It's an important thing cause I'd much rather spend my time working on important things. Thank you.
 
Ranch Hand
Posts: 121
12
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Chan.

Chan Ag wrote:... I do not understand the dependency of this method with the readObject method. I understand it is package private so that immutability cannot be compromised upon to a certain extent ( or would that be wrong? ). But still, why is the method required, remains a puzzle to me.



It is needed in that particular implementation of the readObject method. As you can see, HashMap uses custom serialization protocol (I'll give a reason to do so below). When reading an object, it reads list of keys and values and puts it to a map (using map's own method). Any child should be prepared at this point. For example, LinkedHashMap uses a dummy head/tail values to unify item handling when map is or is not empty. If that dummy values are not initialized, insertion method may throw NullPointerException. And parent dsserialization occurs before child can perform any action. Other approaches are possible. But some approaches will require to reimplement readObject method in each children, for example.

Chan Ag wrote:And why should it be called if 'the constructor will add the entries from the existing map'. I see it is called by other constructors too.


Just because "copy constructor" and children constructor (notably LinkedHashSet) is implemented in some particular way. It is a contract between HashMap and very limited number of it's children. Some HashMap constructors calls internal methods to add all items. Child should be prepared at this point (for example, it should have a linked list initialized). Parent constructors must be called before any children constructor, so LinkedHashSet have no other chances to initialize. It is still possible to do that initialization other way. For example, call a parent's (HashMap) no-arg constructor, initialize internal data and only then call a package-private population method.

These are not coding choices. There are architectural choices. There may be many restrictions and considerations. And while some details are not included in a public API, they may be choosen arbitrary. These may be not the best solutions (and Collections framework ir relatively old), but they still work and there is no reason to change that decisions now.

Chan Ag wrote:Am I missing something here?


As I promised, default serialization is unsafe. I suggest "Effective Java", Chapter 10 "Serialization". In short, all fields read by default deserialization procedure must be considered public. For example you wrote a linked list. Then you may change some bytes in serialized form and read back a loop instead of list! Default serialized form may not be compatible with future class changes. Due to all this you always should consider writing writeObject/readObject methods and using your custom serialized form. HashMap writes a number of entries and then all key-value pairs in iteration order. This allows to change an internal implementation, because serialized form is independent from any internal representation. This also requires to properly reconstruct an object. And that, in order, requires that object to be in an appropriate state to accept new items (linked list initialized in child, etc...).
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Greetings and Thanks so much, Maxim.

I'm still processing what you've said. I shall get back to you.

Chan.

 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry for the late reply, and what a nice response, Maxim. Thanks so much, again.

I've just completed going through the source code of java.util.HashMap and java.util.LinkedHashMap and I'm still in awe of the good practices followed in the source code. Such a thought about implementation.
Your response puts everything in place for me. I understand it all now ( I think so).

Besides the initialization hook ( the void init method ), I liked the indexFor method also for how it works with the rest of the logic. Awesome.

And now I've already started with Effective Java, Chapter 10- Serialization ( I was done till Chapter 9 only, so chapter 10 was next anyway ).

Thanks,
Chan.
 
reply
    Bookmark Topic Watch Topic
  • New Topic