java中的多个泛型类型

时间:2022-01-09 19:22:16

I am new to java and I would like to know how to do this better in java or simpler, cleaner, easier, like having multiple generic types stuff

我是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 个解决方案

#1


0  

Disclaimer: (to stop downvotes ;-))

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

this is just a simple solution to hold an arbitrary number of objects of different type which are retrievable by an actual type in an, again, simple way without guarantee of type safety. Use with caution!

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

Proposed solution:

You could just use a simple List<Object>. As you don't want to make clear what your actual requirements are, that might already suffice you... Here is an example:

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

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);
    }
  }
}

which prints:

sum is 357

Regarding type safety you could improve that a bit by supplying a type during retrieval and fail miserably if the retrieved object isn't of the expected type:

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

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);
    }
  }
}

As others suggest: a builder pattern might also help, but as soon as you add more types or want to remove some you need to adapt the code. And with the builder pattern you still have to write all that generic type information if you want to declare a variable to hold your item. That isn't necessary with this solution. Of course this solution also has some problems: the first variant isn't type safe and could lead to ClassCastException. The second variant could lead to RuntimeException if you want to retrieve an object which hasn't the given type, but at least it is type safe otherwise ;-) So it really depends on what you want to accomplish.

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

If you don't like the RuntimeException in the second variant you could also just use an Optional instead. I omitted that variant deliberately as it makes the code just more verbose. Here is the get-implementation for it:

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

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();
}

Finally, I probably wouldn't use this code in production as it is rather a workaround to spare some code. In production code I prefer type safety over such simplicity.

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

#2


1  

A couple of suggestions you may find useful:

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

  1. You have a case of the "telescoping constructor anti-pattern". The builder design pattern is the usual remedy. As you mention you are looking for a simple solution I would recommend using lombok annotations to implement a builder for your class:

    你有一个“伸缩构*模式”的案例。构建器设计模式是常用的补救措施。正如您所提到的,您正在寻找一个简单的解决方案,我建议您使用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;
    }
    

    You'd have to initialise an Item like this:

    你必须像这样初始化一个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();
    

    Unfortunately type information is duplicated. Note that you can skip fields and initialize in any order. That would be a lot of work with multiple constructors. The other fields e.g. t1, t5 will be left null.

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

  2. Consider adopting Tuple9 from jOOL library. If you look at the source code of Tuple9 it's not simpler than your code. The simplicity of this approach is that someone else has done the implementation instead of you. The library supports up to Tuple16

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

#3


1  

You can either use libraries, code preprocessors or the builder pattern, or if you like to keep things simple you might just create chainable methods that would allow you to set only the attributes you want, in whatever order you want:

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

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
}

Usage:

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");

Or in any other order:

或者以任何其他顺序:

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");

Or just with a few attributes:

或者仅仅具有一些属性:

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

#1


0  

Disclaimer: (to stop downvotes ;-))

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

this is just a simple solution to hold an arbitrary number of objects of different type which are retrievable by an actual type in an, again, simple way without guarantee of type safety. Use with caution!

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

Proposed solution:

You could just use a simple List<Object>. As you don't want to make clear what your actual requirements are, that might already suffice you... Here is an example:

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

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);
    }
  }
}

which prints:

sum is 357

Regarding type safety you could improve that a bit by supplying a type during retrieval and fail miserably if the retrieved object isn't of the expected type:

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

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);
    }
  }
}

As others suggest: a builder pattern might also help, but as soon as you add more types or want to remove some you need to adapt the code. And with the builder pattern you still have to write all that generic type information if you want to declare a variable to hold your item. That isn't necessary with this solution. Of course this solution also has some problems: the first variant isn't type safe and could lead to ClassCastException. The second variant could lead to RuntimeException if you want to retrieve an object which hasn't the given type, but at least it is type safe otherwise ;-) So it really depends on what you want to accomplish.

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

If you don't like the RuntimeException in the second variant you could also just use an Optional instead. I omitted that variant deliberately as it makes the code just more verbose. Here is the get-implementation for it:

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

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();
}

Finally, I probably wouldn't use this code in production as it is rather a workaround to spare some code. In production code I prefer type safety over such simplicity.

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

#2


1  

A couple of suggestions you may find useful:

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

  1. You have a case of the "telescoping constructor anti-pattern". The builder design pattern is the usual remedy. As you mention you are looking for a simple solution I would recommend using lombok annotations to implement a builder for your class:

    你有一个“伸缩构*模式”的案例。构建器设计模式是常用的补救措施。正如您所提到的,您正在寻找一个简单的解决方案,我建议您使用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;
    }
    

    You'd have to initialise an Item like this:

    你必须像这样初始化一个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();
    

    Unfortunately type information is duplicated. Note that you can skip fields and initialize in any order. That would be a lot of work with multiple constructors. The other fields e.g. t1, t5 will be left null.

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

  2. Consider adopting Tuple9 from jOOL library. If you look at the source code of Tuple9 it's not simpler than your code. The simplicity of this approach is that someone else has done the implementation instead of you. The library supports up to Tuple16

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

#3


1  

You can either use libraries, code preprocessors or the builder pattern, or if you like to keep things simple you might just create chainable methods that would allow you to set only the attributes you want, in whatever order you want:

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

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
}

Usage:

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");

Or in any other order:

或者以任何其他顺序:

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");

Or just with a few attributes:

或者仅仅具有一些属性:

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