【问题标题】:Java Selective GenericsJava 选择性泛型
【发布时间】:2013-11-09 22:58:59
【问题描述】:
class A <T> {

    private T field;
}

我知道我可以使用 将类型参数强制为某种有界类型,但是如何强制类型参数 T 仅为 String、Integer、SomeClassB、SomeEnumC 而不是可以用其他参数对其进行参数化吗?

A<SomeClassB> a = new A<SomeClassB>();

是合法的。

A<SomeClassX> a = new A<SomeClassX>();

将是非法的。

我已经尝试使用

测试这些类型
T instanceof SomeEnumC

在A类的构造函数中,但是很乱。

【问题讨论】:

  • 你不能完全按照你的要求去做。你为什么还要呢?这些类的唯一共同方法是来自Object 的方法。
  • T instanceof SomeEnumC 不应该工作。泛型类型信息只存在于编译时,因此没有T 的类型信息可供instanceof 运算符在运行时使用。

标签: java generics types parameters


【解决方案1】:

注意:我同意上面@Jeffrey 的评论,这似乎没有多大意义,因为您似乎无法获得任何有用的类型信息通过做这种限制。我真的很想知道您的用例在这里。


您不能将T 可接受的泛型类型限制为示例中不相关的类列表。您只能使用superextends 限制泛型类型,这意味着它们必须是某些给定类型的超类型或子类型。

但是,由于您似乎希望为T 允许的类数量有限,因此您应该能够枚举所有类。这是我的想法:

public class A<T> {

  /**
   * Private constructor means only nested classes
   * can extend this class. We use this to limit the
   * types that can be used for T.
   */
  private A() { }

  /** Integer version of A */
  public static class IntA extends A<Integer> { }

  /** String version of A */
  public static class StringA extends A<String> { }

}

现在您可以使用static import 导入您想要的A&lt;T&gt; 的任何嵌套版本,或者像这样:import static A.*;

【讨论】:

    【解决方案2】:

    我假设您希望将 A 类导出为 API 的一部分,这就是您希望限制可以作为泛型类型参数传递的类型的原因。

    如果您想要限制 Class A 的类型列表是已知的(并且数量相当少),那么一种解决方法是定义一个包私有接口(这将防止您的包之外的类实现接口):

    interface A <T> {
        T field;
    }
    

    然后您可以简单地为您希望允许的类型编写具体的类。因为没有其他人可以实现您的接口,所以不可能有人根据您不打算允许的类型编写类。

    【讨论】:

    • 我正在为 ARM 汇编代码编写代码生成器。 A 类实际上是一条类似 MOV 的指令,操作数很少,我想将其限制为上述类型以提高类型安全性。
    • 啊,操作码。将您的操作码表示为枚举怎么样?您可以为每个操作代码定义一个或多个实例字段,以指定该代码允许的类型。您无法使用这样的解决方案进行编译时类型检查,但至少它将限制特定类型的问题转变为在 Enum 类中指定元数据的练习。换句话说,不是为每个操作码编写一个类...将每个操作码指定为枚举常量,并在富枚举类型中使用常量关联元数据。
    • 我在上面的代码 sn-p 中发现了自己的错误。接口不能声明实例字段,除非它们是staticfinal。上面给出的接口定义可能无法编译。
    【解决方案3】:

    您不能在编译时对其进行限制,但稍作调整即可在运行时强制执行:

    class A <T> {
        private T field;
        public A(Class<T> c) {
            if (c != String.class | c != Integer.class | c != SomeClassB.class | c != SomeClassC.class)
                throw new IllegalArgumentException();
        }
    }
    

    【讨论】:

      【解决方案4】:

      我认为您的设计可能存在缺陷,而更好的设计根本不需要这样做。但是,如果您真的想走这条路,请使用私有构造函数和工厂方法:

      public class A<T> {
          private T field ;
      
          private A(T t) {
              this.field = t ;
          }
      
          public static A<String> getInstance(String s) {
              return new A<String>(s);
          }
      
          public static A<Integer> getInstance(Integer i) {
              return new A<Integer>(i);
          }
      
          // etc....
      
          // regular instance methods...
      
          public void doStufF() {
              if (field instanceof Integer) { /* ... */ }
              else if (field instanceof String) { /* ... */ }
          }
      }
      

      任何时候你看到丑陋的 if/else 切换类型时,你应该想到“丰富的枚举......”,就像在 scottb 的回答之后的讨论中一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        相关资源
        最近更新 更多