【问题标题】:How to infer method of T from Class<T>如何从 Class<T> 推断 T 的方法
【发布时间】:2017-05-24 14:06:44
【问题描述】:

我有一个实现接口的枚举。枚举:

enum MyEnum implements MyInterface {
    ONE, TWO, THREE;

    @Override
    public MyEnum getFirst() {
        return ONE;
    }
}

界面:

interface MyInterface<T extends Enum<T>> {
    T getFirst();
}

我还有一个带边界的泛型类:

class MyClass <T extends Enum<T> & MyInterface> {
   private T firstElement;
   private Class<T> enumType;

   MyClass (Class<T> enumType) {
      this.enumType = enumType;
   }
}

所以主要思想是将任何enum(实现MyIterface)传递给构造函数,然后使用它的常量。这对我有用。但我也想将第一个元素存储到 firstElement 私有字段中。我试过这样的事情:

firstElement = ((MyInterface)enumType).getFirst();

但仍然没有成功。我无法将java.lang.Class&lt;T&gt; 转换为MyInterface。任何想法如何实现这一目标?提前致谢!

更新:我的问题不在于如何获取第一个枚举常量。我知道.ordinal().values()[0];。我想创建可重用的泛型类并将其与任何枚举一起使用,并由某个接口标记。 好的,不要使用getFirst() 方法。让它成为getDefault()

【问题讨论】:

  • @ΦXocę웃Пepeúpaツ 所有枚举都扩展了该类,它确实有意义:)
  • enumType 是 Class 类型,它不会有你的 enum 方法。只有 MyEnum.ONE、MyEnum.TWO 等可以使用该方法。
  • @niceman 我认为他在这里不需要反射 API,他正试图以一种干净的方式使其通用。
  • @Sikorski hmm OP 缺少 &amp; MyInterface 中的 T,如果包含它,我猜 firstelement.getFirst() 会起作用
  • 不要使用原始类型!试试你的代码,但不要使用原始类型。

标签: java generics enums


【解决方案1】:

我认为您可以使用 Supplier&lt;T&gt; 作为构造函数的参数,而不是 Class&lt;T&gt;

class MyClass<T extends Enum<T> & MyInterface<T>>  {
    private T firstElement;
    private Class<T> enumType;

    @SuppressWarnings("unchecked")
    MyClass (Supplier<T> enumSupplier) {
        T actualEnum = enumSupplier.get();
        this.enumType = (Class<T>) actualEnum.getClass();
        this.firstElement = actualEnum.getFirst();
    }
}

该转换会引发警告,但可以安全地抑制它,因为Supplier&lt;T&gt; 将返回T 的实例,而T 既是Enum&lt;T&gt; 又是MyInterface&lt;T&gt;,所以actualEnum 的类永远是Class&lt;T&gt;

我想建议您进行一些更正:由于MyInterface 是泛型,您应该始终将它与泛型类型一起使用(这就是我将MyClass 声明为MyClass&lt;T extends Enum&lt;T&gt; &amp; MyInterface&lt;T&gt;&gt; 的原因)。 MyEnum 也是如此:它应该定义为 MyEnum implements MyInterface&lt;MyEnum&gt;

完成上述更改后,您现在可以创建MyClass 的实例,如下所示:

MyClass<MyEnum> myClass = new MyClass<>(() -> MyEnum.THREE); // Or ONE or TWO

System.out.println(myClass.firstElement); // ONE

【讨论】:

    【解决方案2】:

    根据您的上下文,我认为您需要getFirst(),因为您想获得枚举的第一个值。但是,您根本不需要getFirst()。你只需要这个:

    class <T extends Enum<T> & MyInterface> MyClass {
       private T firstElement;
       private Class<T> enumType;
    
       MyClass (Class<T> enumType) {
          this.enumType = enumType;
          firstElement = enumType.getEnumConstants()[0];
       }
    }
    

    您可以删除所有课程中的所有getFirst()

    【讨论】:

    • @niceman 呃,恐怕OP会哭说MyInterface是一个标记接口,不能删除。例如CopyOption.
    【解决方案3】:

    您只能在实现MyInterface 的枚举对象上调用getFirst,但不能在其类上调用。你可以写:

    firstElement = enumType.getEnumConstants()[0].getFirst();
    

    【讨论】:

    • 但是由于枚举是有序的,我不明白你为什么想要一个 getFirst() 方法。
    • 谢谢,但我知道.values()[0].ordinal().getEnumConstants()。我的问题不是关于如何获得第一个枚举常量。这是关于泛型的。我会更新我的帖子。
    • @YevhenDanchenko 检查我的答案:enumType.getEnumConstants()[0] 仅用于从Class&lt;T&gt; 获取T 对象,然后在此对象上调用getFirst()(或getDefault())。跨度>
    • 我得到这个解决方案的错误:java.lang.Enum cannot be converted to T
    • @YevhenDanchenko 因为您没有在MyClass 的声明中将&lt;T&gt; 添加到MyInterface:它应该是class MyClass&lt;T extends Enum&lt;T&gt; &amp; MyInterface&lt;T&gt;&gt;
    【解决方案4】:
    interface MyInterface {
        MyInterface getFirst();
    
        MyInterface[] getConstants();
    }
    
    enum MyEnum implements MyInterface {
        ONE, TWO, THREE;
    
        @Override
        public MyInterface getFirst() {
            return ONE;
        }
    
        @Override
        public MyInterface[] getConstants() {
            return new MyInterface[] {ONE, TWO, THREE};
        }
    }
    
    class MyClass {
       private MyInterface firstElement;
    
       MyClass (MyInterface enumType) {
          this.firstElement = enumType.getFirst();
       }
    }
    

    因此,使用上述设计,我认为您可以“将任何枚举(实现 MyInterface)传递给构造函数,然后使用其常量。”

    【讨论】:

    • 我的意思是,当你使用像“enumType”这样的属性时,你没有正确使用接口。因为,在某些时候,您必须编写诸如“if (enumType == SomeType)”或 if (enumType SomeType) 之类的东西,而这些似乎不是一个好的设计。接口主要用于替换此“if else”逻辑(或开关)以进行类型检查。
    • 谢谢。似乎有道理。也许我在建筑方面有问题。
    猜你喜欢
    • 2014-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 2011-09-24
    • 2013-08-01
    • 1970-01-01
    相关资源
    最近更新 更多