• Post Reply Bookmark Topic Watch Topic
  • New Topic

Class loading and Generics  RSS feed

 
Petar Petrovic
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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) ?
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16060
88
Android IntelliJ IDE Java Scala Spring
  • Likes 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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>.
 
Stephan Strauss
Greenhorn
Posts: 14
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dear mate, check p 84 of the Naftalin Java Generics book -- gives some hints concerning this topic.
Cheers and have fun,
Stephan
 
Campbell Ritchie
Marshal
Posts: 56541
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please tell us what the book says; the original poster (=OP) might not have access to it.
 
Stephan Strauss
Greenhorn
Posts: 14
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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

 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!