Class Generics

J

Jason Cavett

Class modelClass = Class.forName(modelResult.getNodeValue());
Class viewClass = Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

I get the warning with the first two lines:
Class is a raw type. References to generic type Class<T> should be
parameterized

So, I tried this...

Class<?> modelClass = Class.forName(modelResult.getNodeValue());
Class<?> viewClass = Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

It removes those warnings, but I then get an error at the third line:
The method put(Class<? extends DataModel>, Class<? extends
PropertiesView>) in the type PropertiesFactory is not applicable for
the arguments (Class<capture#3-of ?>, Class<capture#4-of ?>)

So, I figured maybe there was a way to do something like this:

Class<? extends DataModel> modelClass = (Class<? extends DataModel)
Class.forName(modelResult.getNodeValue());
Class<? extends PropertiesView> viewClass = (Class<? extends
PropertiesView) Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

Which results in the two warnings:
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends DataModel>
and
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends PropertiesView>


At this point, it just seems easiest to use
@SuppressWarnings("unchecked") and ignore the warnings completely.
But, I was wondering if there was something I'm not understanding or
if there's a better way to do what I am trying to accomplish (no
warnings w/ everything cast correctly).


Thanks
 
J

Joshua Cranmer

Jason said:
Class modelClass = Class.forName(modelResult.getNodeValue());
Class viewClass = Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

I get the warning with the first two lines:
Class is a raw type. References to generic type Class<T> should be
parameterized

That is correct, but Sun fails to follow that in at least one case
(Enum.class is a Class said:
So, I figured maybe there was a way to do something like this:

Class<? extends DataModel> modelClass = (Class<? extends DataModel)
Class.forName(modelResult.getNodeValue());
Class<? extends PropertiesView> viewClass = (Class<? extends
PropertiesView) Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

Which results in the two warnings:
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends DataModel>
and
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends PropertiesView>

Almost, but not quite. What you want is:
Class<? extends DataModel> modelClass = Class.forName(
modelResult.getNodeValue()).asSubclass(DataModel.class);

As aforementioned, this breaks down when handling something like enums:
Class<?> clazz = <get from elsewhere>;
Class<? extends Enum<?>> enumClass = clazz.asSubclass(Enum.class);
Class<? extends Enum<?>> enumClass2 = clazz.asSubclass(Enum<?>.class);

Neither of the last two clauses works, although hopefully generics will
be reified in Java 7 and the last one will work (or they could get off
their butts and fix the first syntax).
 
O

Oliver Wong

Jason Cavett said:
Class modelClass = Class.forName(modelResult.getNodeValue());
Class viewClass = Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

I get the warning with the first two lines:
Class is a raw type. References to generic type Class<T> should be
parameterized

So, I tried this...

Class<?> modelClass = Class.forName(modelResult.getNodeValue());
Class<?> viewClass = Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

It removes those warnings, but I then get an error at the third line:
The method put(Class<? extends DataModel>, Class<? extends
PropertiesView>) in the type PropertiesFactory is not applicable for
the arguments (Class<capture#3-of ?>, Class<capture#4-of ?>)

So, I figured maybe there was a way to do something like this:

Class<? extends DataModel> modelClass = (Class<? extends DataModel)
Class.forName(modelResult.getNodeValue());
Class<? extends PropertiesView> viewClass = (Class<? extends
PropertiesView) Class.forName(viewResult.getNodeValue());
factory.put(modelClass, viewClass);

Which results in the two warnings:
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends DataModel>
and
Type safety: Unchecked cast from Class<capture#1-of ?> to Class<?
extends PropertiesView>


At this point, it just seems easiest to use
@SuppressWarnings("unchecked") and ignore the warnings completely.
But, I was wondering if there was something I'm not understanding or
if there's a better way to do what I am trying to accomplish (no
warnings w/ everything cast correctly).

Probably not. Basically, you're telling the compiler that you're
guaranteeing whatever class is named by the expression
modelResult.getNodeValue() will be a subtype of DataModel. There is no way
for the compiler to verify whether or not this is a true statement. The
warning is the compiler's way of telling you it has no way of verifying
the truth-value of that claim, and there is no source code which you can
write which will prove the claim to the compiler.

- Oliver
 
J

Jason Cavett

That is correct, but Sun fails to follow that in at least one case




Almost, but not quite. What you want is:
Class<? extends DataModel> modelClass = Class.forName(
modelResult.getNodeValue()).asSubclass(DataModel.class);

As aforementioned, this breaks down when handling something like enums:
Class<?> clazz = <get from elsewhere>;
Class<? extends Enum<?>> enumClass = clazz.asSubclass(Enum.class);
Class<? extends Enum<?>> enumClass2 = clazz.asSubclass(Enum<?>.class);

Neither of the last two clauses works, although hopefully generics will
be reified in Java 7 and the last one will work (or they could get off
their butts and fix the first syntax).

Awesome, thank you for that help.

I was reading this guide: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
on generics and it does clear up a lot for me. I'm still confused,
though, whether arrays can be made generic.

As far as I can tell (and please correct me if I'm wrong), the entire
point of generics is to provide compile-time type safety. But, from
what I can also tell, arrays ([] not Arrays) types are not known until
runtime. Thus, this defeats the entire purpose of Arrays.

A case in which I'm seeing this problem is:

Class[] classes = { Class1.class, Class2.class, Class3.class };

That statement would consist of the warning: Class is a raw type.
References to generic type Class<T> should be parameterized

So, it's an easy fix if "type unknown" is used:

Class<?>[] classes = { Class1.class, Class2.class, Class3.class };

That makes sense based on my understanding before.

But, it seems...

Class<? extends Whatever>[] classes = { Class1.class, Class2.class,
Class3.class };

gives a compile time error for each class listed in the array.
Is there any way around this? Should I use Collections instead?


Thanks
 
T

Thomas Hawtin

Jason said:
Class<? extends Whatever>[] classes = { Class1.class, Class2.class,
Class3.class };

gives a compile time error for each class listed in the array.
Is there any way around this? Should I use Collections instead?

Arrays are broken.

Given the above line, you could then write:

Object class = NotWhatever.class;
Object[] classesObj = classes;
classesObj[0] = class;
Class<? extends Whatever> oops = classes[0];

So, yes, use proper collections. Keep arrays for primitives and dirty.
low-level optimisations.

Tom Hawtin
 

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

No members online now.

Forum statistics

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

Latest Threads

Top