Re: generics puzzle
In article <45bfae98-a142-469b-9b8b-9aa8a59391f1@n13g2000vbv.googlegroups.com>,
Robert Klemme <shortcutter@googlemail.com> wrote:
On Oct 17, 12:41 pm, blm...@myrealbox.com <blmblm.myreal...@gmail.com>
wrote:
I'm having a bit of trouble with generics, and while I've come
up with ways of getting done what I want to get done, I wonder
whether there's some nice solution that isn't occurring to me.
The basic situation is this:
I have an abstract generic class (call it GThing) with type
parameter T, which has a method (call it set()) that takes a
parameter of type T and another method (call it modified()) that
returns a result of type T. I also have some classes that extend
GThing and specify its type parameter, and code that is meant
to operate on lists of instances of these various subclasses.
What I would *like* to be able to do is construct a list of
GThing<?> objects and then do to each element of it something
like the following:
element.set(element.modified())
but the compiler objects to that, which I find reasonable enough,
though I'm not enough of a generics expert to really articulate
what the problem is. (I have a feeling that this "type erasure"
thing, which I understand dimly at best, comes into it. :-)? )
The reason is the ? in the type: the compiler does not know the type.
The very moment you declare a List<GThing<?>> the type of T is unknown
even though it's the same instance. Unknown types cannot be
compatible yet you try to do invoke a method with argument type ? with
a parameter of type ? and since "? incompatible to ?" it is not
allowed.
Nice job of putting into words my vague idea about what's wrong;
thanks!
You are basically doing this (list1) but bounding does not help
(neither way, list2 and list3); only concrete types are able to ensure
type compatibility:
import java.util.ArrayList;
import java.util.List;
public class GenericsProblemRK {
public static void main(String[] args) {
final List<List<?>> list1 = new ArrayList<List<?>>();
for (final List<?> l : list1) {
l.add(l.get(0)); // error
final Object x = l.get(0); // OK
l.add(x); // error
}
final List<List<? extends String>> list2 = new ArrayList<List<?
extends String>>();
for (final List<? extends String> l : list2) {
l.add(l.get(0)); // error
final Object x = l.get(0); // OK
l.add(x); // error
}
final List<List<? super String>> list3 = new ArrayList<List<? super
String>>();
for (final List<? super String> l : list3) {
l.add(l.get(0)); // error
final Object x = l.get(0); // OK
l.add(x); // error
}
final List<List<String>> list4 = new ArrayList<List<String>>();
for (final List<String> l : list4) {
l.add(l.get(0)); // OK
}
}
}
One fix is to just introduce a method setFromModified() in GThing,
but that doesn't appeal to me. An ugly-hack fix is to add to
GThing a set() method that takes an Object and typecasts it,
but -- yuck, right?
In your case since apparently you want to update internally why not
just introduce
public void update() {
set(modified());
}
I'm not sure I can say why this doesn't appeal to me -- something
about not wanting to clutter up GThing with unnecessary methods.
This will safely compile. Basically this is what you did with
setModified() in the wrapper class. All other approaches will be
hacky (i.e. involve explicit casting, using Object parameters or
return values etc.).
Yeah, maybe .... In my "real" code (quotation marks because it's
a toy project embarked on for entertainment and a bit of education)
the method in the wrapper class does more than just call modified()
and then set(). I don't know that that matters much, though. I do
have a couple of different "call sites" (to use another poster's term)
that need similar functionality, so maybe it *does* go in GThing.
Well, like I said, "entertainment and a bit of education", and for
me that seems to involve -- the coding equivalent of periodically
rearranging the furniture, maybe.
--
B. L. Massingill
ObDisclaimer: I don't speak for my employers; they return the favor.