【问题标题】:Guava TypeToken and generic classesGuava TypeToken 和泛型类
【发布时间】:2014-10-01 07:49:08
【问题描述】:

我在我的项目中使用 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&lt;String&gt;() 实例化一个对象,然后调用getRecordType(),我希望得到java.lang.String,而不是得到java.lang.Object

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

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

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

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

【问题讨论】:

  • “这是 TypeToken 的预期行为吗?” 是的。

标签: java generics guava


【解决方案1】:

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

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

JVM 看到类似的东西

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

由于擦除。

但是当你声明时

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

那么在MyStringImpl的定义中记录了使用的泛型,可以通过Class#getGenericSuperclass()获取。这就是TypeToken 背后的魔力(部分)。

【讨论】:

    【解决方案2】:

    要完成这项工作,您需要在实例化 MyGenericClass 时使用相同的匿名子类技巧:

    new MyGenericClass<String>() {}
    

    如果你这样做,那么你会得到getRecordType 返回的StringJavaDocs for that TypeToken constructor 中解释了这样做的必要原因。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多