-1

Can you fix what I've done to Josh Blocks Effective Java heterogeneous container? I'm toying with the idea storing String.class in stringClass but it doesn't work. Can you explain why and fix it?

package heterogeneous;

import java.util.HashMap;
import java.util.Map;

//Typesafe heterogeneous container pattern - implementation
public class TypedValue {
    private Map<Class<?>, Object> typedValues = new HashMap<Class<?>, Object>();

    public <T> TypedValue(Class<T> type, T instance) {
        put(type, instance);
    }
    public <T> T put(Class<T> type, T instance) {
        if (type == null)
            throw new NullPointerException("Type is null");

        @SuppressWarnings("unchecked")
        T oldValue = (T) typedValues.put(type, instance); 
        return oldValue; 
    }
    public <T> T get(Class<T> type) {
        return type.cast(typedValues.get(type));
    }

    // Typesafe heterogeneous container pattern - client
    public static void main(String[] args) {
        TypedValue j = new TypedValue(String.class, "Java");
        TypedValue i = new TypedValue(Integer.class, 0xcafebabe);
        TypedValue t = new TypedValue(Class.class, TypedValue.class);

        String favoriteString = j.get(String.class);
        int favoriteInteger = i.get(Integer.class);
        Class<?> favoriteClass = t.get(Class.class);

        // .-=== Fix and explain what was wrong ==-. //
        Class<?> stringClass = String.class;

        //Type mismatch: cannot convert from capture#1-of ? to String 
        favoriteString = j.get(stringClass); 
        // ^-=== Fix and explain what was wrong ==-^ //

        System.out.printf( "%s %x %s%n", 
                           favoriteString, 
                           favoriteInteger, 
                           favoriteClass.getName() );
    }
}
candied_orange
  • 7,036
  • 2
  • 28
  • 62

1 Answers1

2

By using a wildcard here

Class<?> stringClass = String.class;

you're explicitly saying you don't know (care) about the underlying generic type. It can be anything. But your method

favoriteString = j.get(stringClass); 

depends on that type to determine its return type. Since it's unknown, the return type will be inferred to ? as well. You can't assign a value of some unknown type to a variable of type String.

Change it to

Class<String> stringClass = String.class;
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • That works. Is it any different than Class extends String>? (which also works) – candied_orange Sep 04 '14 at 03:16
  • @CandiedOrange Yes, there is a difference in the overall concept of generics, though less at the `Class` level because of how it uses its type parameter. Wildcards are discussed in more detail [here](http://stackoverflow.com/questions/252055/java-generics-wildcards) and [here](http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs), among others. – Sotirios Delimanolis Sep 04 '14 at 03:20