Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2006

Tip: Looking for answers? Try searching our database.

subclassing and generics

Thread view: 
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.