subclassing and generics

H

Henry Townsend

I've kind of backed into generics ... I was developing in
Eclipse using JDK 1.4 with quite a lot of classes which extend
Collections. At some point I started running with JDK 1.5 but Eclipse
was still set to compile in 1.4 compatibility mode. Then I wanted to
make some use of the new printf capabilities and had to allow Eclipse to
compile in "new" (1.5) mode to get it. As a result, I suddenly have LOTS
of warnings being generated by the old-style use of Collections with
casting, such as:

"Type safety: The method add(Object) belongs to the raw type ArrayList.
References to generic type ArrayList<E> should be parameterized."

I'm trying to study up on generics now that I'm in the brave new(ish)
world of JDK 1.5. But in the meantime I'd like a little help trimming
down the huge set of warnings. I can't quite figure out the pattern for
subclassing a Collection; all the tutorials I've found focus more on
writing new code using generics.

So, if I have a simple class:

public class Foo extends ArrayList {
public boolean add(Object o) {
// do something extra
return super(o);
}
}

with some methods overridden and some not (as above), could someone
please show me all the places to put <E> and so on to make Eclipse be
happy again, at which point I can learn generics under a little less
pressure?

TIA,
HT
 
O

Oliver Wong

Henry Townsend said:
I've kind of backed into generics ... I was developing in
Eclipse using JDK 1.4 with quite a lot of classes which extend
Collections. At some point I started running with JDK 1.5 but Eclipse
was still set to compile in 1.4 compatibility mode. Then I wanted to
make some use of the new printf capabilities and had to allow Eclipse to
compile in "new" (1.5) mode to get it. As a result, I suddenly have LOTS
of warnings being generated by the old-style use of Collections with
casting, such as:

"Type safety: The method add(Object) belongs to the raw type ArrayList.
References to generic type ArrayList<E> should be parameterized."

I'm trying to study up on generics now that I'm in the brave new(ish)
world of JDK 1.5. But in the meantime I'd like a little help trimming down
the huge set of warnings. I can't quite figure out the pattern for
subclassing a Collection; all the tutorials I've found focus more on
writing new code using generics.

So, if I have a simple class:

public class Foo extends ArrayList {
public boolean add(Object o) {
// do something extra
return super(o);
}
}

with some methods overridden and some not (as above), could someone please
show me all the places to put <E> and so on to make Eclipse be happy
again, at which point I can learn generics under a little less pressure?

Perhaps something like:

public class FooList<E> extends ArrayList<E> {
public boolean add(E o) {
// do something extra
return super.add(o);
}
}

The idea is rather than actually specifying a type (e.g. I'm a FooList
of Strings, or I'm a FooList of Users), you use a name like E (i.e. I'm an
FooList of something, and let's call that something E for now), and then use
E where ever you would normally use the type of the thing you're an FooList
of.

So for example, the parameter to your add method is of type E, because
you're only allowing clients to add objects of type E into this FooList.

BTW, if you're using Eclipse, and you just want to get rid of the
warnings, you can right click on the project, and configure the compiler
settings to ignore generic-warnings.

- Oliver
 
P

Philipp Leitner

you can actually surpress compiler warnings by using Java 5
annotations, so if the only thing you're worried about is Eclipse
shutting up for the moment this may be fine for you.

Otherwise using generics with collections is very easy. Just compare
the 1.4 and 5 code below:

Java 1.4: List myStringList = new LinkedList();
Java 5: List<String> myStringList = new LinkedList<String>();

Got the point? It is very easy to do, even if you /don't/ understand
generics.

/philipp
 
H

Henry Townsend

Philipp said:
you can actually surpress compiler warnings by using Java 5
annotations, so if the only thing you're worried about is Eclipse
shutting up for the moment this may be fine for you.

Otherwise using generics with collections is very easy. Just compare
the 1.4 and 5 code below:

Java 1.4: List myStringList = new LinkedList();
Java 5: List<String> myStringList = new LinkedList<String>();

Got the point? It is very easy to do, even if you /don't/ understand
generics.

For the record, I do understand the *concept* of generics. And I know
how to *use* them as above because the tutorials I've read have shown
that use case. What I'm struggling with is the syntax of subclassing in
the context of generics; everything I've tried has caused inscrutable
compile errors so I end up going back to the warnings.

And yes, I'm sure the warnings can be turned off but I have no backward
compatibility requirement with 1.4.2 so I'd prefer to get comfortable
with generics and use them going forward. I just want to restore the
code base to a stable warning-free state first.

I'm in the process of looking at Oliver Wong's suggestion and will come
back if I can't make it work. Thanks to both.

HT
 
H

Henry Townsend

Henry said:
I'm in the process of looking at Oliver Wong's suggestion and will come
back if I can't make it work. Thanks to both.

OK, specific example. Here's a class fragment that compiles and works
with 1.4, no warnings:

public class FooClass extends TreeMap {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

As you can see this is a TreeMap of "PTX" objects, where the keys are
actually an attribute of the value so I can use a one-argument "add"
method rather than the two-arg "put". When I switch to 1.5 mode I get
the "Type safety" warning mentioned upthread. So I try parameterizing it:

public class FooClass<K,V> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

but that results in a hard error "The method put(K, V) in the type
TreeMap<K,V> is not applicable for the arguments (String, PTX)". Now, I
clearly am passing it a String and a PTX, so what have I done wrong?

Thanks,
HT
 
T

Timo Stamm

Henry said:
OK, specific example. Here's a class fragment that compiles and works
with 1.4, no warnings:

public class FooClass extends TreeMap {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

As you can see this is a TreeMap of "PTX" objects, where the keys are
actually an attribute of the value so I can use a one-argument "add"
method rather than the two-arg "put". When I switch to 1.5 mode I get
the "Type safety" warning mentioned upthread. So I try parameterizing it:

public class FooClass<K,V> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

but that results in a hard error "The method put(K, V) in the type
TreeMap<K,V> is not applicable for the arguments (String, PTX)". Now, I
clearly am passing it a String and a PTX, so what have I done wrong?


public class FooClass<String, PTX> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}
 
H

Henry Townsend

Timo said:
public class FooClass<String, PTX> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

Thanks, but that just turned 1 error into 20 (literally!). I'll try
again, extracting it out of Eclipse and into a simple command line/javac
test. Here are two trivial classes:

// FooClass.java
import java.util.*;

public class FooClass extends TreeMap {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

// PTX.java
import java.util.*;

public class PTX extends TreeSet {
public String getID() {
return "XXX";
}
}

using 1.5.0_05 they compile with a warning using javac:

% javac FooClass.java
Note: FooClass.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

% javac -Xlint:unchecked FooClass.java
FooClass.java:5: warning: [unchecked] unchecked call to put(K,V) as a
member of the raw type java.util.TreeMap
this.put(ptx.getID().toString(), ptx);

OK, so this is similar to what Eclipse says. Upon adding the parameters
as suggested I get3 hard errors:

% javac -Xlint:unchecked FooClass.java
FooClass.java:3: cannot find symbol
symbol: class K
public class FooClass<String, PTX> extends TreeMap<K, V> {
^
FooClass.java:3: cannot find symbol
symbol: class V
public class FooClass<String, PTX> extends TreeMap<K, V> {
^
FooClass.java:5: cannot find symbol
symbol : method getID()
location: class java.lang.Object
this.put(ptx.getID().toString(), ptx);
 
P

Patricia Shanahan

Henry said:
I've kind of backed into generics ... I was developing in
Eclipse using JDK 1.4 with quite a lot of classes which extend
Collections. At some point I started running with JDK 1.5 but Eclipse
was still set to compile in 1.4 compatibility mode. Then I wanted to
make some use of the new printf capabilities and had to allow Eclipse to
compile in "new" (1.5) mode to get it. As a result, I suddenly have LOTS
of warnings being generated by the old-style use of Collections with
casting, such as:

"Type safety: The method add(Object) belongs to the raw type ArrayList.
References to generic type ArrayList<E> should be parameterized."

I realize you want to learn generics and move to them at some point.

However, Eclipse does have a compilation option to ignore "Unchecked
generic type operations" warnings, without having to annotate all the
code and without suppressing any other warning. You can turn the warning
back on whenever you want to work on the generics issue.

Patricia
 
T

Timo Stamm

Sorry Henry, I wasn't paying attention. Of course it should look like this:

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


Timo
 
O

Oliver Wong

Timo Stamm said:
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);
}
}

To the OP:

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.

- Oliver
 
H

Henry Townsend

Oliver said:
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.

HT
 
D

Dale King

Timo said:
public class FooClass<String, PTX> extends TreeMap<K,V> {
public void add(PTX ptx) {
this.put(ptx.getID().toString(), ptx);
}
}

I believe that should be:

public class FooClass<String, PTX> extends TreeMap<String, PTX>
 
T

Timo Stamm

Dale said:
I believe that should be:

public class FooClass<String, PTX> extends TreeMap<String, PTX>


No, this declares "String" and "PTX" as type parameters for FooClass.
What I intended to do was to parameterize TreeMap with the types String
and PTX. FooClass itself doesn't require parameterization.


Timo
 
D

Dale King

Timo said:
No, this declares "String" and "PTX" as type parameters for FooClass.
What I intended to do was to parameterize TreeMap with the types String
and PTX. FooClass itself doesn't require parameterization.

I realized that after I sent it. I was only looking at the fact that you
used K, V in the tree map and wasn't paying attention to the fact that
you parameterized FooClass.
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Henry Townsend schreef:
Yes he did.


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.

H.
- --
Hendrik Maryns

==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFEfVwVe+7xMGD3itQRAvE7AJ9u5qerwV55C74lIiinJE9Gn5TxJwCfdHTN
qpN64NJEnUykn0v5/Wvv73Q=
=A3h7
-----END PGP SIGNATURE-----
 
C

Chris Uppal

Hendrik said:
I am very surprised nobody gave the advise to not use inheritance at
all.

+1. Including the surprise ;-)

It /might/ be that the OP's uses of FooClass should also "know" that the
objects are Maps (or even TreeMaps), but -- like you -- I doubt it.

Delegation is
the better option, and it also makes the generics issue easier.

Sometimes having a difficulty with generics can indicate a flawed design.
Essentially the Java compiler is telling you "your design sucks" (of course,
/I/ would never be that rude ;-).

Unfortunately, it can be difficult to tell whether a generics problem is
actually caused by iffy design, or whether it's just another flaw in generics
themselves. But they can help diagnose an unclean design, or promote a clean
one.

(There now, I've gone and said something positive about generics! I promise
it won't soon happen again ;-)

-- chris
 
D

Dale King

Hendrik said:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Henry Townsend schreef:

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);
}

}
 
H

Henry Townsend

Dale said:
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.

While comments on my skill level are probably correct, it may be worth
pointing out that much of my code uses delegation as well. My tendency
(I hesitate to say "philosophy" because I'm not that experienced) is to
start out with inheritance while roughing out the design precisely
because it doesn't require generating lots of delegation methods, then
doing a refactoring exercise and converting to delegation as appropriate
when things are more stable. At which point I can just remove the
"extends" clause and Eclipse is happy to point out (with error messages)
the exact set of delegation methods required. The alternative is to
generate a bunch of delegators up front, which again Eclipse is happy to
help me with, but I've gone that route before and find myself spending a
lot of time adding and subtracting methods as the design changes[*]. Is
this such a bad plan?

[*] Of course you could go to the next step and say that coding
shouldn't start till the design is more stable, but this is a personal
project I'm working on in my spare time and I don't have time for the
waterfall method.

HT
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Henry Townsend schreef:
Dale said:
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.

While comments on my skill level are probably correct, it may be worth
pointing out that much of my code uses delegation as well. My tendency
(I hesitate to say "philosophy" because I'm not that experienced) is to
start out with inheritance while roughing out the design precisely
because it doesn't require generating lots of delegation methods, then
doing a refactoring exercise and converting to delegation as appropriate
when things are more stable. At which point I can just remove the
"extends" clause and Eclipse is happy to point out (with error messages)
the exact set of delegation methods required. The alternative is to
generate a bunch of delegators up front, which again Eclipse is happy to
help me with, but I've gone that route before and find myself spending a
lot of time adding and subtracting methods as the design changes[*]. Is
this such a bad plan?

I agree that goes in the right direction, but really, if I think of it I
have never needed to extend a java base class. Most of the time, you
only need two or three methods, in which case the delegation is not much
of a problem.
[*] Of course you could go to the next step and say that coding
shouldn't start till the design is more stable, but this is a personal
project I'm working on in my spare time and I don't have time for the
waterfall method.

I won’t start commenting on such things until I have had the discipline
myself to follow it...

H.
- --
Hendrik Maryns

==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFEfboxe+7xMGD3itQRArHrAJkBQZyqoT9mY5fkSAp7oXFvwZIolQCfQRST
bEZlMowgeZTz+Nps17vpWio=
=lcyi
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

generics puzzle 57
eclipse and un-generics 2
Generics and for each 12
Generics 24
can this be done with generics? 32
Generics Amanuensis? 2
Generics and subclassing -- best etiquette 7
Tree design with generics 2

Members online

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top