Java Forum / General / May 2006
subclassing and generics
Henry Townsend - 30 May 2006 17:11 GMT 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
Oliver Wong - 30 May 2006 17:32 GMT > I've kind of backed into generics ... I was developing in > Eclipse using JDK 1.4 with quite a lot of classes which extend [quoted text clipped - 26 lines] > 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
Philipp Leitner - 30 May 2006 17:37 GMT 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
Henry Townsend - 30 May 2006 18:34 GMT > you can actually surpress compiler warnings by using Java 5 > annotations, so if the only thing you're worried about is Eclipse [quoted text clipped - 8 lines] > 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
Henry Townsend - 30 May 2006 18:57 GMT > 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
Timo Stamm - 30 May 2006 19:30 GMT Henry Townsend schrieb:
>> 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. [quoted text clipped - 22 lines] > 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); } }
Henry Townsend - 30 May 2006 20:00 GMT > 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);
Timo Stamm - 30 May 2006 22:08 GMT Henry Townsend schrieb:
>> public class FooClass<String, PTX> extends TreeMap<K,V> { >> public void add(PTX ptx) { >> this.put(ptx.getID().toString(), ptx); >> } >> } 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
Oliver Wong - 30 May 2006 22:09 GMT > 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
Henry Townsend - 30 May 2006 22:17 GMT >> public class FooClass<String, PTX> extends TreeMap<K,V> { >> public void add(PTX ptx) { [quoted text clipped - 9 lines] > } > } 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 [quoted text clipped - 8 lines] > 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
Hendrik Maryns - 31 May 2006 10:04 GMT Henry Townsend schreef:
>>> public class FooClass<String, PTX> extends TreeMap<K,V> { >>> public void add(PTX ptx) { [quoted text clipped - 27 lines] > 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
Chris Uppal - 31 May 2006 13:03 GMT > 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
Dale King - 31 May 2006 14:24 GMT > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 [quoted text clipped - 47 lines] > 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); }
}
 Signature Dale King
Henry Townsend - 31 May 2006 15:44 GMT > 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
Hendrik Maryns - 31 May 2006 16:45 GMT Henry Townsend schreef:
>> 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 [quoted text clipped - 14 lines] > 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
Dale King - 31 May 2006 00:48 GMT > 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>
 Signature Dale King
Timo Stamm - 31 May 2006 01:17 GMT Dale King schrieb:
>> public class FooClass<String, PTX> extends TreeMap<K,V> { >> public void add(PTX ptx) { [quoted text clipped - 5 lines] > > 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
Dale King - 31 May 2006 01:26 GMT > Dale King schrieb: >>> [quoted text clipped - 11 lines] > 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.
 Signature Dale King
Thomas Weidenfeller - 31 May 2006 09:22 GMT > 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. http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
 Signature The comp.lang.java.gui FAQ: ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq http://www.uni-giessen.de/faq/archiv/computer-lang.java.gui.faq/
Patricia Shanahan - 30 May 2006 20:11 GMT > I've kind of backed into generics ... I was developing in > Eclipse using JDK 1.4 with quite a lot of classes which extend [quoted text clipped - 7 lines] > "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
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|