Re: subclassing and generics



Hendrik Maryns wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Henry Townsend schreef:
Oliver Wong wrote:
"Timo Stamm" <timo.stamm@xxxxxxxx> wrote in message
news:447c8f63$0$11073$9b4e6d93@xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
public class FooClass<String, PTX> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}
I think you mean:

public class FooClass extends TreeMap<String, PTX> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}
Yes he did.

In this case, FooClass is not generic at all. That is, the client
CANNOT specify that "This is a FooClass of Buttons". They deal with
FooClasses, which are hardcoded to deal with Strings and PTXes. So
FooClass itself isn't generic.

However, under the covers, FooClass uses TreeMap, and TreeMap *IS*
generic. In this case, you're using TreeMaps mapping strings to PTXes,
but someone else might use the exact same TreeMap to map Integers to
Users, for example.

That's why you need to use type name arguments for TreeMap, but not
for FooClass.
Thanks to you both. All warnings are gone and I have the beginnings of
wisdom on the use of generics.

I am very surprised nobody gave the advise to not use inheritance at
all. Indeed, from your snippets, I see no need for it. Delegation is
the better option, and it also makes the generics issue easier. Thus:
>
public class FooClass {

private TreeMap<String, PTX> map = new TreeMap<String, PTX>();

public void add(PTX ptx) {
map.put(ptx.getID().toString(), ptx);
}

}

Seems much cleaner design to me: the clients of FooClass do not have to
know that you are using a TreeMap, it is none of their business (unless
you explicitly want them to be able to use foo.put("blabla", new PTX()),
which I suppose you don’t.

I did think about saying something about it. But then decided it wasn't worth going down that road based on a few lines of code.

While it is cleaner it is probably more work for the OP because he would have to implement a bunch of Map methods and have them delegate to the contained map. Judging by the OP's skill level I wasn't ready to bite off that additional bit of instruction.

The canonical example of why inheritance is overused is java.util.properties, which extends Hashtable instead of containing a Map. That means that you can only have a Hashtable as the backing store (which means all accesses are synchronized). You cannot substitute a LinkedHashMap instead.

It might be better to also to do the following to allow the type of Map used to be changed:

public class FooClass {

private final Map<String, PTX> map;

public FooClass( Map<String, PTX> map )
{
this.map = map;
}

public FooClass()
{
this( new TreeMap<String, PTX>() );
}

public void add(PTX ptx) {
map.put(ptx.getID().toString(), ptx);
}

}

--
Dale King
.


Quantcast