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 [email protected] (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

猜你喜欢

转载自blog.csdn.net/hellozhxy/article/details/82020039