Help with Java Generics...

I was hoping you guys might be able to give me a little help with Java Generics. I'm trying to track down a null pointer exception in my pluggable rendering code, and I think it may result from improper use of Generics.

In one of my classes I store a HashMap. The keys for this HashMap are Strings. The values stored in the HashMap are the references to any class which implements an interface. (I'll call the interface SomeInterface for this example.) I want the HashMap to be able to store any implementation of the SomeInterface.

Eclipse is giving me an error on this statement. It says that it "Can't instantiate the type HashMap<String,? extends SomeInterface>".

I'm guessing this is becuase I'm trying to use an interface and not a class as the upper bound of my wild card in the generics declaration. Is there a way around this, other than defining a default class that must be extended by all other implementations of SomeInterface.

I'm really surprised that you can't use interfaces in this type of statement. Unless of course, I've got another mistake staring me in the face.

Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them. - Laurence J. Peter

Garrett Rowe

Ranch Hand

Posts: 1296

posted 10 years ago

The wildcard in private HashMap<String, ? extends SomeInterface> indicates a parameterized HashMap where the second parameter is some specific implementation (or subclass if SomeInterface were a concrete class) of SomeInterface. For instance if you have an implementing class:

and a method signature:

then a HashMap<String, SomeClass> would qualify as a parameter to this method. However you wouldn't be ablt to add anything to the map because the specific type of the class that implements SomeInterface isn't known at compile time.

Also since parametrized types arent covariant, a HashMap<String, SomeClass> could not be passed to a method that expected a HashMap<String, SomeInterface>.

I'm not sure if that was helpful or more confusing...

Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them. - Laurence J. Peter

This made the error disappear in Eclipse, although I don't know if the code will work properly when compiled. I'll let you find out.

What I'm trying to do is have a HashMap that can store any class implementing SomeInterface.I also need to be able to add instances of classes implementing SomeInterface to. I think I can accomplish this with the above definition of the HashMap and a genric method that adds elements to the HashMap. I'll report back on how this works.

Thanks again for the help.

Landon

Garrett Rowe

Ranch Hand

Posts: 1296

posted 10 years ago

Then what you really want is a HashMap<String, SomeInterface>, the wildcards serve no purpose here.

Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them. - Laurence J. Peter

Landon Blake

Ranch Hand

Posts: 44

posted 10 years ago

Garrett,

I can see now that you were correct. I didn't need to use wildcards because I was dealing with an interface.

I think i'd need to use the wildcard if I wanted to allow subclasses of a class, instead of implementations of an interface.

Thanks,

Landon [ May 17, 2007: Message edited by: Landon Blake ]

Garrett Rowe

Ranch Hand

Posts: 1296

posted 10 years ago

I think i'd need to use the wildcard if I wanted to allow subclasses of a class, instead of implementations of an interface.

No, a reference of type HashMap<String, Object> will compile without warning and allow you to store any type of Object as a value in the map. For the most part, I usually see wildcards in method parameters. Since generic types aren't covariant you cant do this:

ArrayList<Object> objectList = new ArrayList<String>();//NOT ALLOWED

An ArrayList<String> is not a subtype of ArrayList<Object>. Therefore, an ArrayList<String> is not a valid argument for a method who's signature is:

But in most cases what is really meant by that line of code is "This method will accept a parameterized ArrayList of any type and we will treat the elements of that ArrayList as Objects". With generics in Java one way to express that is: