JSON 序列化與反序列化(二)使用TypeReference 構建類型安全的異構容器


1. 泛型通常用於集合,如Set和Map等。這樣的用法也就限制了每個容器只能有固定數目的類型參數,一般來說,這也確實是我們想要的。

然而有的時候我們需要更多的靈活性,如數據庫可以用任意多的Column,如果能以類型安全的方式訪問所有Columns就好了,幸運的是

有一種方法可以很容易的做到這一點,就是將key進行參數化,見以下代碼

 1 public class Favorites {
 2     private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
 3     public <T> void setFavorite(Class<T> klass, T thing) {
 4         favorites.put(klass, thing);
 5     }
 6     public <T> T getFavorite(Class<T> klass) {
 7         return klass.cast(favorites.get(klass));
 8     }
 9     public static void main(String[] args) {
10         Favorites f = new Favorites();
11         f.setFavorite(String.class, "Java");
12         f.setFavorite(Integer.class, 0xcafebabe);
13         String s = f.getFavorite(String.class);
14         int i = f.getFavorite(Integer.class);
15     }
16 }

 

2.不足之處

There is a limitation to this pattern.

//You can't add your favorite List<String> to a Favorites because you simply can't make a type token for a generic type.

f.setFavorite(List<String>.class, Collections.emptyList());

 

3.改進

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * References a generic type.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public abstract class TypeReference<T> {

    private final Type type;
    private volatile Constructor<?> constructor;

    protected TypeReference() {
        Type superclass = getClass().getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
    }

    /**
     * Instantiates a new instance of {@code T} using the default, no-arg
     * constructor.
     */
    @SuppressWarnings("unchecked")
    public T newInstance()
            throws NoSuchMethodException, IllegalAccessException,
                   InvocationTargetException, InstantiationException {
        if (constructor == null) {
            Class<?> rawType = type instanceof Class<?>
                ? (Class<?>) type
                : (Class<?>) ((ParameterizedType) type).getRawType();
            constructor = rawType.getConstructor();
        }
        return (T) constructor.newInstance();
    }

    /**
     * Gets the referenced type.
     */
    public Type getType() {
        return this.type;
    }

    public static void main(String[] args) throws Exception {
        List<String> l1 = new TypeReference<ArrayList<String>>() {}.newInstance();
        List l2 = new TypeReference<ArrayList>() {}.newInstance();
    }
}

 

參考:

  • com.google.common.reflect.TypeToken<T>
  • com.fasterxml.jackson.core.type.TypeReference

原文:Super Type Tokens

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM