Guava TypeToken和泛型类

时间:2014-09-30 15:06:29

标签: java generics guava

我在项目中使用了Guava TypeToken类,但是我得到了意想不到的结果。

我有MyGenericClass<T>

public class MyGenericClass<T> implements MyInterface {

    private TypeToken<T> recordType;

    public MyGenericClass(String name) {
        this.recordType = new TypeToken<T>(getClass()) {};

        // ...
    }

    // ...

    @SuppressWarnings("unchecked")
    protected Class<T> getRecordType() {
        return (Class<T>) recordType.getRawType();
    }
}

因此,如果我通过new MyGenericClass<String>()实例化对象,然后调用getRecordType(),我希望获得java.lang.String,而不是java.lang.Object

但是,如果我扩展泛型类:

public class MyStringImpl extends  MyGenericClass<String> {
    // ...
}

并实例化这个新类:new MyStringImpl()然后我得到了正确的结果。

为什么会这样?这是TypeToken的预期行为吗?

2 个答案:

答案 0 :(得分:14)

在Ian的回答中添加一些无聊的细节:如果TypeToken按预期方式工作会很好,但这是不可能的。当你宣布

public class MyGenericClass<T> implements MyInterface {...}

JVM看起来像

public class MyGenericClass<Object> implements MyInterface {...}

由于擦除。

但是当你宣布

public class MyStringImpl extends MyGenericClass<String> {...}

然后在MyStringImpl的定义中,记录了使用的泛型,并且可以通过Class#getGenericSuperclass()获得。这是TypeToken背后的魔力(<一部分)。

答案 1 :(得分:13)

要实现此功能,在实例化MyGenericClass时需要使用相同的匿名子类技巧:

new MyGenericClass<String>() {}

如果您这样做,那么String会返回getRecordType。必要的原因在JavaDocs for that TypeToken constructor

中进行了解释
  

客户端创建一个空的匿名子类。这样做会将type参数嵌入到匿名类的类型层次结构中,这样我们就可以在运行时重新构建它,尽管擦除了。