Guava TypeToken和泛型类

dav*_*ooh 6 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

public class MyStringImpl extends  MyGenericClass<String> {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

maa*_*nus 14

为Ian的回答添加一些无聊的细节:如果TypeToken以你期望的方式工作会很好,但这是不可能的.当你申报时

public class MyGenericClass<T> implements MyInterface {...}
Run Code Online (Sandbox Code Playgroud)

JVM看起来像

public class MyGenericClass<Object> implements MyInterface {...}
Run Code Online (Sandbox Code Playgroud)

由于擦除.

但是当你宣布时

public class MyStringImpl extends MyGenericClass<String> {...}
Run Code Online (Sandbox Code Playgroud)

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


Ian*_*rts 13

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

new MyGenericClass<String>() {}
Run Code Online (Sandbox Code Playgroud)

如果你这样做,那么你会得到String回报getRecordType.这个必要的原因在该构造函数JavaDocs中进行了TypeToken解释.

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