unchecked conversion problem

R

rschmid-google

I have finally been allowed to upgrade to Java5 and I just finished
fixing some 1200 parameterization warnings which has really improved
the code. I have one, ONE, left and I'm not sure it can be fixed.

I have the following object heierarchy;

SourceMatch
CMatch extends SourceMatch
DMatch extends SourceMatch

SMatchService<T extends SourceMatch>
CMatchService extends SMatchService<CMatch>
DMatchService extends SMatchService<DMatch>

in SMatchService is the following method

public abstract List<T> getMatchingSources(args) {}

which is implemented in the subclass services thus;

public List<CMatch> getMatchingSources(args) {}

and

public List<DMatch> getMatchingSources(args) {}

yet the following code throws an unchecked conversion warning;

SMatchService sourceMatchService = null;
if (c) sourceMatchService = new CMatchService();
else if (d) sourceMatchService = new DMatchService();

List<SourceMatch> sourceList = =
sourceMatchService.getMatchingSources(args);

I have tried using wildcard parameters but my understanding is
imperfect at best.

I suspect that the problem is really architectural but I wanted to find
out if there is a way to make this work.

Any help is appreciated.
 
N

Niklas Matthies

yet the following code throws an unchecked conversion warning;

SMatchService sourceMatchService = null;
if (c) sourceMatchService = new CMatchService();
else if (d) sourceMatchService = new DMatchService();

List<SourceMatch> sourceList = =
sourceMatchService.getMatchingSources(args);

Try this:

SMatchService<?> sourceMatchService = null;
if (c) sourceMatchService = new CMatchService();
else if (d) sourceMatchService = new DMatchService();

List<? extends SourceMatch> sourceList =
sourceMatchService.getMatchingSources(args);

-- Niklas Matthies
 
L

Lasse Reichstein Nielsen

yet the following code throws an unchecked conversion warning;

SMatchService sourceMatchService = null;

Here SMatchService lacks a type parameter. Try:
SMatchService said:
if (c) sourceMatchService = new CMatchService();
else if (d) sourceMatchService = new DMatchService();

List<SourceMatch> sourceList = =
sourceMatchService.getMatchingSources(args);

And here the list you get will be:
List<? extends SourceMatch> sourceList =
sourceMatchService.getMatchingSources(args);

/L
 
R

rschmid-google

Niklas said:
Try this:

SMatchService<?> sourceMatchService = null;
if (c) sourceMatchService = new CMatchService();
else if (d) sourceMatchService = new DMatchService();

List<? extends SourceMatch> sourceList =
sourceMatchService.getMatchingSources(args);

-- Niklas Matthies

Great! Except now;

sourceList = new ArrayList<SourceMatch>();
sourceList.add(new SourceMatch());

throws an error.

I can work around this by creating a new list and copying one into the
other but that is wasteful. What's the right syntax?
 
N

Niklas Matthies

Niklas Matthies wrote: : :
Great! Except now;

sourceList = new ArrayList<SourceMatch>();
sourceList.add(new SourceMatch());

throws an error.

I can work around this by creating a new list and copying one into
the other but that is wasteful. What's the right syntax?

You need to use a second variable declared with a different type:

List<SourceMatch> sourceList2 = new ArrayList<SourceMatch>();
sourceList2.add(new SourceMatch());

List<SourceMatch> means that the list can contain _any_ instances
of SourceMath. List<? extends SourceMatch> on the other hand means
that the list can contain only instances of _some specific_ (but
unspecified) subtype of SourceMatch. The '?' might actually be
SourceMatch itself, but it also might be CMatch or DMatch. That's
why the compiler doesn't allow you to add an arbitrary SourceMatch
instance to such a list, because the list could for example really be
a List<CMatch>, to which it's only permissible to add CMatch objects.
Consider:

List<CMatch> cList = new ArrayList<CMatch>();
List<? extends SourceMatch> sourceList = cList; // fine
sourceList.add(new SourceMatch()); // (*)
// oops, now cList contains a SourceMatch object although
// it is a List<CMatch>!
CMatch cMatch = cList.get(i); // throws ClassCastException!

That's why the line (*) is rejected by the typechecker.

To get a better understanding of generics I suggest you take a look
at http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html .

-- Niklas Matthies
 
L

Lasse Reichstein Nielsen

Great! Except now;

sourceList = new ArrayList<SourceMatch>();
sourceList.add(new SourceMatch());

throws an error.

As it should. ArrayList<SourceMatch> is not assignable to
List<? extends SourceMatch>.

You can do
sourceList = new ArrayList<? extends SourceMatch>();
but you can't add a SourceMatch to that (or anything at all).

Remember, a List<SourceMatch> and a List<CMatch> are not assignable
to each other. The former allows you to put SourceMatch'es into it,
the latter doesn't. And the latter guarantees that what you take
out of it is a CMatch, the former doesn't.

If you want a variable to hold both of the above list types, it
needs to be something like List<? extends SourceMatch> (which is
a supertype of both). However, you cannot add elements to that list,
since it might be both a List<CMatch> or a List<DMatch>, which cannot
contain the same elements.

Instead, you could just let the getMatchingSources return a
List<SourceMatch>.

/L
 
R

rschmid-google

Lasse said:
As it should. ArrayList<SourceMatch> is not assignable to
List<? extends SourceMatch>.

You can do
sourceList = new ArrayList<? extends SourceMatch>();
but you can't add a SourceMatch to that (or anything at all).

Remember, a List<SourceMatch> and a List<CMatch> are not assignable
to each other. The former allows you to put SourceMatch'es into it,
the latter doesn't. And the latter guarantees that what you take
out of it is a CMatch, the former doesn't.

If you want a variable to hold both of the above list types, it
needs to be something like List<? extends SourceMatch> (which is
a supertype of both). However, you cannot add elements to that list,
since it might be both a List<CMatch> or a List<DMatch>, which cannot
contain the same elements.

Ah, Thank you! That was the point I had forgotten. Once I understood
it became obvious that I could move the actual code into a new
parameterized method in SourceMatch.
 

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

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top