Java generics with unbounded wildcard?

后端 未结 3 1575
孤城傲影
孤城傲影 2021-01-03 13:24

I have an interface to convert object to string:

public interface Converter {
    String asString(T object);
}

And a map to store

相关标签:
3条回答
  • 2021-01-03 13:54

    First, you should encapsulate the map inside a helper class like this, whose operations preserve the invariant (that Class<T> maps to Converter<T>):

    public class ConverterMap {
        Map<Class<?>, Converter<?>> converterMap = new HashMap<Class<?>, Converter<?>>();
        public <T> void addConverter(Class<T> clazz, Converter<T> converter) {
            converterMap.put(clazz, converter);
        }
        @SuppressWarnings("unchecked")
        public <T> Converter<T> getConverter(Class<T> clazz) {
            return (Converter<T>)converterMap.get(clazz);
        }
    }
    

    Now, to break down the task, let's take the small step of writing a function that takes any object and converts it based on the converter map (assuming the object's class is in the converter map):

    ConverterMap cm = new ConverterMap;
    private static String convert(Object x);
    

    This seems simple, but is harder than it looks, because you will run into a special case of the Java type system in how it types .getClass(). You will have the problem of convincing the compiler that x is an instance of the parameter of x.getClass(). The best way to solve this is:

    @SuppressWarnings("unchecked")
    private static <T> String convert2(Class<T> clazz, Object x) {
        return cm.getConverter(clazz).asString((T)x);
        // you can alternately do clazz.cast(x) instead of the unchecked cast (T)x
    }
    private static String convert(Object x) {
        return convert2(x.getClass(), x);
    }
    

    And then you can solve the rest of the problem:

    for (Object datum : data) {
        stringData.add(convert(datum));
    }
    
    0 讨论(0)
  • 2021-01-03 13:58

    You are facing issue called wildcard capture. Java is unable to identify the type that will be received from the List<?> data. Try refactoring your code in any of the two ways

    Method 1: Change your interface as below

    interface Converter {
        String asString(Object object);
    }
    

    Method 2: Helper method to capture wild card by type inference

    Create an helper method as below,

    // Helper method created so that the wildcard can be captured
    // through type inference.
    private <T> void helper(List<T> data) {
        Map<Class<?>, Converter<T>> converterMap = null;
        List<String> stringData = null;
    
        for (T datum : data) {
            stringData.add(converterMap.get(datum.getClass()).asString(datum));
        }
    }
    

    Call this helper method as below

    List<?> data = fetchData();
    helper(data);
    
    0 讨论(0)
  • 2021-01-03 13:59

    You should change the code like this:

    public interface Converter {
        String asString(Object object);
    }
    

    I think it will work.

    0 讨论(0)
提交回复
热议问题