如何在运行时从泛型类型定义和运行时类型参数构建Java类型对象



假设一个泛型类型声明(Java)

class Foo<T> {
    public T bar;
}

在运行时,我如何实例化一个Type对象,该对象表示在特定类型T上参数化的Foo(也仅在运行时已知)?

我想我理解你的问题。您想要序列化Foo<T>,并且在运行时有T的类对象(但在编译时它不是固定的)。因此,Gson中建议的创建TypeToken的匿名子类的解决方案不起作用,因为这需要在编译时对参数化类型(例如Foo<String>)进行硬编码,如果您使用类似Foo<T>的东西,它就不起作用。

但是,让我们看看Gson站点上的TypeToken方法实际实现了什么。创建TypeToken的匿名子类的对象,然后使用其getType()方法请求其类型参数。类的超类是其元数据的一部分,并包括其超类的泛型参数。因此,在运行时,它可以查看自己的继承层次结构,并确定您为TypeToken使用了什么类型的参数,然后返回该类型的java.lang.reflect.Type实例(如果对其进行参数化,则该实例将是ParameterizedType实例)。一旦得到这个Type实例,就应该将其作为toGson()的第二个参数传递。

我们所需要做的就是找到另一种方法来创建这个ParameterizedType实例。ParameterizedType是一个接口,但不幸的是,公共Java API没有提供任何具体的实现或任何动态创建ParameterizedType的方法。在私有的Sun API和Gson代码中(例如这里),似乎有一个名为ParameterizedTypeImpl的类。您可以简单地复制代码并将其重命名到自己的类中。然后,要在运行时创建一个代表Foo<String>Type对象,只需执行类似new ParameterizedTypeImpl(Foo.class, new Type[]{String.class}, null)(未测试)

的操作

比方说我们谈论的是List<String>
你可以构建这样的东西:

    Type type = new ParameterizedType() {
            public Type getRawType() {
                return List.class;
            }
            public Type getOwnerType() {
                return null;
            }
            public Type[] getActualTypeArguments() {
                return new Type[] { String.class};
            }
        };

如果您需要从JSON进行反序列化,则可以通过调用gson.fromJson 来使用此Type

通常的类型擦除方法是:

class Foo<T> {
    Class<T> clazz;
    public Foo(Class<T> c) {
        clazz = c;
    }
    public T bar {
        return clazz.newInstance();
    }
}

如果你的T没有args构造函数,你可以使用Class对象上的反射来做一些更有趣的事情;一旦有了Class<T>的实例,就可以获得一个实例。

我在gson身上也遇到了这个问题。我最终得到了这个:

public class JsonWrapper {
    private String className;
    private String json; // the output of the gson.toJson() method
}

当我需要取消序列化时,我做了一个Class.forName(className),然后我就可以调用gson库的fromJson()方法了。

我不敢相信gson在本机上不支持这一点——这似乎是一件显而易见的事情……获取一些json并将其转换为对象,而事先不知道它是哪个类。

Gson确实为此提供了一个解决方案:https://sites.google.com/site/gson/gson-user-guide#TOC-串行化和反串行化通用

当然,这只不过是Bohemian的解决方案(您仍然需要以某种方式传递类型参数),而是自动为您完成的。

其他人都说了什么:)。要实例化的类需要在运行时可用。有很多方法可以做到这一点:将类或类名放在工厂本地的变量中,有一个受保护的方法,如果你需要在很多不同的地方创建一个"对象工厂"类,等等。这就是bean框架所做的工作,所以如果你正在使用一个,那么可以通过配置它来实现。

它似乎比大多数人想象的要简单:

Type collectionType = new TypeToken<ArrayList<Person>>(){}.getType();
ArrayList<Person> persons = gson.fromJson(response, collectionType);

无需按照newacct的建议复制ParameterizedTypeImpl类。

最新更新