java中的多个泛型类型

时间:2017-04-21 13:54:32

标签: java

我是java的新手,我想知道如何在java中更好地做到这一点,或者更简单,更清洁,更容易,比如有多种泛型类型的东西

public class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9>{
    private T1 t1;
    private T2 t2;
    private T3 t3;
    private T4 t4;
    private T5 t5;
    private T6 t6;
    private T7 t7;
    private T8 t8;
    private T9 t9;

    public Item(T1 t1){
        this(t1, null, null, null, null, null, null, null, null);
    }
    public Item(T1 t1, T2 t2){
        this(t1, t2, null, null, null, null, null, null, null);
    }

    public Item(T1 t1, T2 t2, T3 t3){
        this(t1, t2, t3, null, null, null, null, null, null);
    }

    public Item(T1 t1, T2 t2, T3 t3, T4 t4){
        this(t1, t2, t3, t4, null, null, null, null, null);
    }
    ...

3 个答案:

答案 0 :(得分:1)

您可能会发现一些有用的建议:

  1. 你有一个“telescoping constructor anti-pattern”的案例builder design pattern是通常的补救措施。如你所说,你正在寻找一个简单的解决方案,我建议使用lombok注释为你的类实现一个构建器:

    @Getter
    @Builder
    class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> {
        private T1 t1;
        private T2 t2;
        private T3 t3;
        private T4 t4;
        private T5 t5;
        private T6 t6;
        private T7 t7;
        private T8 t8;
        private T9 t9;
    }
    

    你必须像这样初始化Item

    Item<String, Integer, Double, String, Long, Long, Long, Long, Long> item =
        Item.<String, Integer, Double, String, Long, Long, Long, Long, Long>builder()
                .t4("text").t2(42).t3(3.14159).build();
    

    不幸的是,类型信息是重复的。请注意,您可以跳过字段并按任何顺序初始化。对于多个构造函数来说,这将是很多工作。其他领域,例如t1t5将保留为空。

  2. 考虑从jOOL library采用Tuple9。如果你看source code of Tuple9,它并不比你的代码简单。这种方法的简单性在于其他人已经完成了实现,而不是你。该库最多支持Tuple16

答案 1 :(得分:1)

您可以使用库,代码预处理器或构建器模式,或者如果您希望保持简单,您可以创建可链接的方法,只允许您按照您想要的顺序设置所需的属性:

public class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> {
    private T1 t1;
    private T2 t2;
    private T3 t3;
    private T4 t4;
    private T5 t5;
    private T6 t6;
    private T7 t7;
    private T8 t8;
    private T9 t9;

    public Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> t1(T1 t1) {
        this.t1 = t1;
        return this;
    }

    public Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> t2(T2 t2) {
        this.t2 = t2;
        return this;
    }

    // TODO: rest of methods
}

用法:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t1("hello")
    .t2(0.123)
    .t3(123)
    .t4(123L)
    .t5(123_456L)
    .t6(123_456_789L)
    .t7(654_321L)
    .t8(321L)
    .t9("goodbye");

或以任何其他顺序:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t6(123_456_789L)
    .t2(0.123)
    .t3(123)
    .t5(123_456L)
    .t7(654_321L)
    .t8(321L)
    .t4(123L)
    .t1("hello")
    .t9("goodbye");

或只是有一些属性:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t6(123_456_789L)
    .t2(0.123)
    .t3(123);

答案 2 :(得分:0)

免责声明:(停止downvotes; - ))

这只是一个简单的解决方案,可以保存任意数量的不同类型的对象,这些对象可以通过实际类型以一种简单的方式检索,而不保证类型安全。请谨慎使用!

建议的解决方案:

您可以使用简单的List<Object>。由于您不想明确您的实际要求,这可能已经足够您......以下是一个示例:

public class Item {
  List<Object> items = new ArrayList<>();

  public <T> Item(T... items) { // well... could also just be Object
     Collections.addAll(this.items, items);
  }

  public <T> T get(int index) {
     return (T) items.get(index); // unsafe of course... but no requirement said something about type safety ;-)
  }

  public static void main(String[] args) {
    Item item = new Item("sum", 123L, 234L, true);

    if (item.get(3)) {
      long sum = item.<Long>get(1) + item.<Long>get(2);
      System.out.println(item.get(0) + " is " + sum);
    }
  }
}

打印:

sum is 357

关于类型安全,您可以通过在检索期间提供类型来改善这一点,如果检索到的对象不是预期类型,则可能会失败:

public class Item {
  List<Object> items = new ArrayList<>();

  public <T> Item(T... items) {
    Collections.addAll(this.items, items);
  }

  public <T> T get(int index, Class<T> type) {
    Object item = items.get(index);
    if (type.isInstance(item)) {
      return type.cast(item);
    }
    throw new RuntimeException("failing miserably as index " + index + " isn't of type " + type);
  }

  public static void main(String[] args) {
    Item item = new Item("sum", 123L, 234L, true);

    if (item.get(3, Boolean.class)) {
      long sum = item.get(1, Long.class) + item.get(2, Long.class);
      System.out.println(item.get(0, String.class) + " is " + sum);
    }
  }
}

正如其他人所说:构建器模式也可能有所帮助,但只要添加更多类型或想要删除某些类型,就需要调整代码。如果要声明一个变量来保存item,那么使用构建器模式仍然需要编写所有泛型类型信息。这个解决方案不是必需的。当然,这个解决方案也存在一些问题:第一个变体不是类型安全的,可能导致ClassCastException。如果你想要检索一个没有给定类型的对象,第二个变体可能会导致RuntimeException,但至少它是类型安全的;否则;-)所以它实际上取决于你想要完成什么。

如果您不喜欢第二个版本中的RuntimeException,您也可以使用Optional。我故意省略了这个变体,因为它使代码更加冗长。以下是get - 它的实现:

public <T> Optional<T> get(int index, Class<T> type) {
  Object item = items.get(index);
  if (type.isInstance(item)) {
    return Optional.of(type.cast(item));
  }
  return Optional.empty();
}

最后,我可能不会在生产中使用此代码,因为它是一种解决方法,可以节省一些代码。在生产代码中,我更喜欢类型安全而非简单。