当前位置: 首页 > 知识库问答 >
问题:

无法从Guava解析泛型参数TypeToken

陆宇航
2023-03-14

我正在为Selenium测试框架开发一个构建泛型菜单的框架,我一直在使用Guava TypeToken来解析泛型参数的类型,但现在我遇到了一个问题,类型标记无法解析参数:

我有一个<code>抽象<code>基<code>类<code>用于生成菜单选项的生成器:

public abstract class AbstractMenuOptionBuilder<O extends IClickable>  {

    protected final TypeToken<AbstractMenuOptionBuilder<O>> typeToken = new
            TypeToken<AbstractMenuOptionBuilder<O>>(getClass()) { };

    public abstract O create();
}

这是构建器的具体

public class MenuOptionBuilder<O extends IClickable> extends AbstractMenuOptionBuilder<O> {

    public O create() {
        TypeToken<?> genericOptionParam = typeToken.resolveType(AbstractMenuOptionBuilder.class.getTypeParameters()[0]);

        Class<O> optionClass;

        try {

            optionClass = (Class<O>) Class.forName(genericOptionParam.getType().getTypeName());

             <.... snip ....>

        } catch(ClassNotFoundException e) {
            log.catching(e);
            return null;
        }
    }
}

我有一个用于菜单的抽象,它有一个返回菜单选项列表的方法:

public abstract class AbstractMenu<O extends IClickable> {

    public final List<O> getOptions() {

        //This is where my plan doesn't work. The runtime type is given by
        //a concrete menu class which extends AbstractMenu, but that runtime
        //type doesn't seem to pass through to the abstract base class for the builder.
        MenuOptionBuilder<O> builder = new MenuOptionBuilder<O>(new MenuOptionBean()){};

             <.... snip ....>
    }

}

我有一个具体的菜单< code >类,它< code >扩展了它:

   //The runtime type of 'Link' is not known by the type token that is supposed to
   //resolve it in the abstract builder base class.
   public SimpleMenu extends AbstractMenu<Link> {
       <.... snip ....>
   }

我原以为<code>菜单选项生成器,但它没有,而是解析为<code>O,泛型类型参数的名称,而不是其运行时类型<code>Link 。如果像这样创建一个附加的基<code>类

public abstract class AbstractSimpleLinkedMenu extends AbstractMenu<Link> {

    public final List<Link> getOptions() {

        MenuOptionBuilder<Link> builder = new MenuOptionBuilder<Link>(new MenuOptionBean()){};
        <.... snip ....>
    }
} 

我不希望添加额外的基类,如AbstractSimpleLinkedMenu,那么这里是否有我遗漏或做得不正确的地方?我认为抽象构建器的匿名内部类会知道运行时类型,但如果使用泛型参数声明构建器,则不会。运行时类型由具体菜单classSimpleMenu指定,但它似乎没有过滤到菜单选项的抽象构建器类。

共有1个答案

史洛城
2023-03-14

这就是<code>TypeToken</code>的“黑客”的工作原理。它使用类#getGenericSuperclass()(或getGenericSuperInterface)。它的javadoc声明

如果超类是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数

在这种情况下,即O,这里

public abstract class AbstractMenuOptionBuilder<O extends IClickable>

您得到的是源代码中硬编码的内容。如果您将< code>Link硬编码为类型参数,就像这里一样

MenuOptionBuilder<Link> builder = 
    new MenuOptionBuilder<Link>(new MenuOptionBean()) {};

然后您将获得Link

既然这样

MenuOptionBuilder<O> builder = 
    new MenuOptionBuilder<O>(new MenuOptionBean()){};

你已经硬编码了O,所以这就是你会得到的。

下面是我写的一些关于类型标记的东西:

  • 具有动态 ArrayList 项类型的 Gson 类型
  • 是否可以使用 Gson.fromJson() 来获取 ArrayList
 类似资料:
  • 问题内容: 我正在开发一个用于为Selenium测试框架构建通用菜单的框架,并且我一直在使用Guava TypeToken来解析通用参数的类型,但是现在我遇到了一个问题,其中类型令牌无法解析参数: 我有一个生成菜单选项的构建器基础: 这是建造者的具体做法: 我有一个菜单基础,它具有一种返回菜单选项列表的方法: 我有一个具体的菜单是它: 我曾期望in 中的变量可以解析为通用类型参数的名称,而不是其运

  • 我需要 Kotlin 中的一个集合来仅包含实现给定接口的元素。 例如:包含动物集合的地图: 通过阅读文档、博客和SO问题,我编写了使用Generics in关键字的代码: 现在我想在Test类中添加一个读取“data”内容的方法,例如将其打印到控制台: 如果我这样做,我会遇到编译错误: 我的解决方案是强制我的动物进入一个ArrayList 但是我不确定这是编写这种代码的最好方式。有没有更好的方式告

  • 本页包含内容: 泛型形参子句 泛型实参子句 本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。 关于 Swift 语言的泛型概述,见泛型(第二部分第22章)。 泛型形参子句 泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约

  • 问题内容: 我想知道是否有可能编写一个接受多种通用类型的函数,如下所示: 那行得通吗?每个参数中的泛型是否意味着每个参数必须具有与泛型相同的类型T? 问题答案: 是的-可能的(虽然不是使用方法签名),是的,使用签名的类型必须相同。 使用给定的签名,必须在呼叫站点将其与单个类型(例如 或 )相关联。但是,您可以声明采用多个类型参数的方法签名 请注意,在上面的签名中,我已经声明了类型以及签名本身。因此

  • 问题内容: 在C#中,我实际上可以这样做: 但是由于某种原因,我无法使其在Java中工作。 我要做的是在超类上创建一个静态方法,以便可以将子类转换为XML。 问题答案: 称为: 或更明确地: 更令人困惑的是,您可以拥有既构造泛型类型又具有泛型参数的构造函数。不记得该语法,也从未在愤怒中使用过它(无论如何,最好还是使用静态创建方法)。 强制转换是不安全的,并且您不能编写T.class。因此,将T.c