Forums Register Login

Class loading and Generics

+Pie Number of slices to send: Send
Hi,

I need some help.

I want to load a class that implements the Validator interface and then call its validate method.

public interface Validator<T>{
void validate(Map<String,T> request);
}

1)
Validator<?> validator=Class.forName("org.matanundjaranen.DateValidator").newInstance();
//Map<String,?> request
validator.validate(request); // **ERROR**

2)
Validator validator=Class.forName("org.matanundjaranen.DateValidator").newInstance(); //warning
//Map<String,Object> request
validator.validate(Map<String,Object> request); // **WARNING**

Is there a better solution then 2) ?
4
+Pie Number of slices to send: Send
When you load a class dynamically through reflection, you're not going to escape having to do some casts, since the compiler doesn't know what the type of the class is that you're going to load at runtime, so it can't check the types.

In your second solution you are using the raw type Validator (a raw type is a generic type where you don't specify the type arguments). Don't use raw types - the only reason raw types exist is for compatibility with old Java code (from Java 1.4 and older, when generics didn't yet exist in the language), and you shouldn't use raw types in new code.

So, let's look at your first solution. That doesn't work, because you use Validator<?> and you can't pass that a Map<String, ?>, because the compiler can't be sure that the "?" you used for Validator stands for the same type as you used for the "?" in the Map.

You probably made this mistake because of a common misunderstanding about generic wildcards: Validator<?> does not mean: a Validator that I can pass any kind of object to. It means: a Validator that needs objects of some specific, but unknown type. You can't pass anything to the validate() method because the compiler doesn't know what the unknown type is.

If you know the type in advance, you can cast the Validator with the right type:

This will still give you a warning ("unchecked cast"), which you can optionally suppress:

If you don't know the type in advance, then you can cast to Validator<Object>.
+Pie Number of slices to send: Send
Dear mate, check p 84 of the Naftalin Java Generics book -- gives some hints concerning this topic.
Cheers and have fun,
Stephan
+Pie Number of slices to send: Send
Please tell us what the book says; the original poster (=OP) might not have access to it.
+Pie Number of slices to send: Send
 

Campbell Ritchie wrote:Please tell us what the book says; the original poster (=OP) might not have access to it.



Well, I am still too much a beginner but I will give my best in trying to explain -
because I think, that my exposure of a possible misunderstanding will help me
as well. So please correct me - I am very thankful if I can learn something
here.

As far as I understand it ...

The idea of wild cards is described earlier in the book is really important
to understand this problem here as already described by Jesper. What the
book explains is the following:

The wild card is NO type parameter, it is an actual type parameter
(as Joshua Bloch would name it, or a specialized type argument
(as Angelika Langer would name it): The specialization is called wild
card type
, what is probably not a good name for it (cause it is already
an "instantiation"). So as Jesper already said, the wildcard (?) stands for
the information: there exists an unknown type Tx for the given generic type
that makes it (the imagined parameterized generic type) a valid reference to the given
object instance.

e.g. having List<?> list (that is nothing than List<? extends Object>) says

There exists one Tx out of T, for that List<Tx> is a valid parameterized type
to the provided object. But Tx is unknown to the compiler - it just knows, that the list
contains only Tx type elements.

And now the first very important consequence: Each ? of the declarations generates
one separate compiler capture. This is I think, what Jesper said, when telling

the compiler can't be sure that the "?" you used for Validator stands for
the same type as you used for the "?" in the Map



But the example above has another speciality. The documentation of the
newInstance() claims to return T. This is different to the java.lang.reflect.Array.newInstance()
method, that claims to return Object (no, not Object[] as one would assume) -
this because of primitive type arrays that need to be treated also in this case.

Both variants need to be casted to the actual parameterized type - and this is an
unchecked (and therefore evil (holy me ;) cast). The point here is parameterized,
because at runtime this information is gone, so the given back instance is just
that one reflected by the class object - so in Petar's example, the Validator.


From the design point of view the book tells us, that in cast of unchecked casts, stay with
the rule of truth in advertising, that is:

The reified type of an array must be a subtype of the erasure of the static type



meaning, when using reflection whatever, make sure, that the function delivering the reference
to an object has the type of the instance. Inside this function you need to use unchecked casts,
what means *danger* but is necessary in case you want to develop e.g. a toArray method that
takes a List<Type> and gives back an array Type[].

Uff ... so .. and please now slaughter ... for sure I missed something or used somewhere a
wrong terminus technicus.

Cheers and have a nice evening,
Stephan

Aaaaaand ... we're on the march. Stylin. Get with it tiny ad.
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com


reply
reply
This thread has been viewed 1072 times.
Similar Threads
Basic question on objects and references to objects
Please help me to solve the singleton dilema
Map of Class object keys and type parameterized with that class
Problems implementing plug-ins....!
Reflection
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 29, 2024 09:43:33.