【问题标题】:Java generic field declarationJava 泛型字段声明
【发布时间】:2015-11-07 15:10:43
【问题描述】:

在一个没有泛型类型的类中,我想声明一个相当复杂的泛型字段,类似于:

public class Client {
    private Map<Class<T extends Serializable>, List<Consumer<S extends T>>> classToConsumerTry1;

    private <T extends Serializable, S extends T> Map<Class<T>, List<Consumer<S>>> classToConsumerTry2;
}

问题是java编译器不允许我:)

所以我的问题是如何正确引入 T 和 S 而不向我的类 Client 添加类型。

我的目标是强制 ClassSerializable 的子类型,而 Consumer 是您为 Class 选择的类的子类型。

【问题讨论】:

  • 你为什么不想扩展你的类声明?
  • 因为我的 Map 应该能够包含不同的 T 和 S 值,而不仅仅是 Client 声明中定义的值。
  • 您的地图成员在哪里初始化?在构造函数中?在某些 setter 方法中?
  • 我不太了解您的要求 - 您在创建对象时设置通用字段类型是 Java 概念,您想实现什么?
  • 我通过 Socket 接收 Serializables 并希望像这样很好地处理它们:classToConsumer.get(serial.getClass()).get(i).accept(serial);

标签: java generics types field


【解决方案1】:

你不能。您唯一的选择是在 Client 类声明中声明泛型类型参数。如果您的 Client 类没有泛型类型参数,则其成员不能是泛型的。您必须在类成员的声明中使用实际类型。

【讨论】:

    【解决方案2】:

    您必须在某处引入类型参数,以便您可以在类成员的定义中使用它们。

    只能在类级别或方法级别引入类型参数。在您的情况下,它应该在类级别:

    public class Client<T extends Serializable, S extends T> {
        private Map<Class<T>, List<Consumer<S>>> classToConsumerTry1;
    
        private Map<Class<T>, List<Consumer<S>>> classToConsumerTry2;
    }
    

    然而,这意味着对于两个成员(classToConsumerTry1classToConsumerTry2),TS 是相同的。如果您希望它们不同,则必须从两个不同的类中获取这两个值,这两个类都使用单独的类型参数进行参数化。

    【讨论】:

    • 另外,作为附加步骤,这个类可以声明为protected class ClientImpl,为了隐藏泛型,可以声明一个暴露的public class Client extends ClientImpl&lt;Serializable, Serializable&gt;
    【解决方案3】:

    您不能直接在字段上执行此操作,但您可以通过泛型方法维护您的类型策略(它们甚至可以存在于非泛型类中):

    @SuppressWarnings("rawtypes")
    private Map<Class, List> map;
    
    public <T extends Serializable> void put(Class<T> key, List<Consumer<? extends T>> value) {
        map.put(key, value);
    }
    
    @SuppressWarnings("unchecked")
    public <T extends Serializable> List<Consumer<? extends T>> get(Class<T> key) {
        return map.get(key);
    }
    

    【讨论】:

      【解决方案4】:

      你不能按照你想要的方式完成。但是您可以设置为Object 并进行转换。其他 hacky 答案包括使用 List&lt;? extends Serializable&gt;(但这仅适用于一个 extends),然后使用 add() 您的项目或执行类似操作的内部类:

      private class Foo<T> {
              T obj;
      }
      

      这样您就可以在内部访问/变异obj

      【讨论】:

        【解决方案5】:

        作为注释,可以将类类型声明为字段(因为谷歌向我发送了这个无关的问题......)

          Class<? extends MyInterface> myCurrentClass = MyImplementation.class;
        

        【讨论】:

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