JSON 序列化与反序列化:使用TypeReference 构建类型安全的异构容器

1. 泛型通常用于集合,如Set和Map等。这样的用法也就限制了每个容器只能有固定数目的类型参数,一般来说,这也确实是我们想要的。

然而有的时候我们需要更多的灵活性,如数据库可以用任意多的Column,如果能以类型安全的方式访问所有Columns就好了,幸运的是

有一种方法可以很容易的做到这一点,就是将key进行参数化,见以下代码

复制代码

 1 public class Favorites {
 2     private Map, Object> favorites = new HashMap, Object>();
 3     public  void setFavorite(Class klass, T thing) {
 4         favorites.put(klass, thing);
 5     }
 6     public  T getFavorite(Class 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 to a Favorites because you simply can't make a type token for a generic type.

f.setFavorite(List.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 {

    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 l1 = new TypeReference>() {}.newInstance();
        List l2 = new TypeReference() {}.newInstance();
    }
}

复制代码

 

参考:

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

原文:Super Type Tokens

 

你可能感兴趣的:(Java)