【问题标题】:Enforce same type for generic function (best practice)对泛型函数强制执行相同类型(最佳实践)
【发布时间】:2014-04-15 14:38:34
【问题描述】:

我有一个通用函数,它接收两个应该属于同一类型的参数。

到目前为止,函数看起来像这样:

void <T> copyTo1(Class<T> type, T destination, T source) {
    // Do stuff
}

这很好用,但我认为这不是实现我的目标的正确方法,因为函数中不会使用类型。所以我寻找了另一种解决方案并想出了这个:

void <T, S extends T> copyTo2(T destination, S source) {
    // Do stuff
}

这两个函数允许的调用类型如下所示:

copyTo1(Object.class, new Object(), new Object()); // Okay
copyTo1(Object.class, new Object(), new String()); // Okay
copyTo1(Object.class, new String(), new Object()); // Okay
copyTo1(String.class, new String(), new String()); // Okay
copyTo1(String.class, new String(), new Date()); // Not okay

copyTo2(new Object(), new Object()); // Okay
copyTo2(new Object(), new String()); // Okay
copyTo2(new String(), new Object()); // Not okay
copyTo2(new String(), new Date()); // Not okay

第二种选择更严格,这对我来说非常好。

现在的问题是:应该首选哪种方法?还是还有一个我没看到?

非常感谢。


仅作记录:我知道我可以像这样定义和使用函数...

void <T> copyTo(T destination, T source) {
    // Do stuff
}

...

this.<String> copyTo(new String(), new String());

但我希望用户立即看到他正在尝试的操作何时不允许。当他省略类型的定义时,情况并非如此。

【问题讨论】:

  • IMO 不是关于最佳实践,而是关于要求。您希望destinationsource 之间有什么样的关系,请相应地使用类型参数。
  • @RohitJain 我同意,选择最适合的那个。如果更严格的方法有效,那就去吧!
  • 我忘了说type在具体实现中不会用到。
  • 我更喜欢第二种选择,但这最终是具体要求的问题。
  • @LeonardBrünings 我选择了第二个版本。

标签: java generics methods


【解决方案1】:

问题是“应该是同一类型”到底是什么意思? Java 中的所有引用都是Object 的实例,因此根据定义,它们总是“属于同一类型”。由于任何引用类型都是Object 的子类型,因此它应该是:

void copyTo2(Object destination, Object source)

Java 中的泛型类型参数旨在提供约束,以便您可以在不进行强制转换的情况下执行某些操作。但是,在这种情况下,您对类型参数没有限制,因此除了 Object 提供的东西之外,无论如何您都无法对类型 T 执行任何操作。

【讨论】:

  • 该函数应该从同一类的另一个实例的一个实例复制属性。有点像BeanUtils.copyProperties,但更简单(无需转换)并忽略空值。由于我们要传输特定于类的属性,因此传递两个只有 Object 作为共同祖先的不同类型是没有意义的。
  • @Zeeker:但是您对参数的类型一无所知,那么除非您使用反射,否则您如何访问“属性”?如果您使用反射,则无论如何都没有类型安全。泛型是为了类型安全,除了Object 类型的两个参数之外,没有更多的类型安全可以实现。您的要求是矛盾的,因为“传递两个只有 Object 作为共同祖先的不同类型”传递两个“相同类型”的东西,因为该类型可能是 Object,并且任何引用类型都是隐式的可转换为Object
  • 耶,我正在使用反射来访问对象的属性。当然,我们可以将Object 的属性复制到Object,但这有什么用呢?我可以看到并理解这种混淆,但是通过使用泛型,我至少可以确保传递的参数不只是将 Object 作为共同祖先,因此复制属性实际上是有意义的。
  • @Zeeker:“但通过使用泛型,我至少可以确保传递的参数不只是将 Object 作为共同祖先,因此复制属性实际上是有意义的。”不,你不能。
  • 我可以。在第二个版本中,如果您将 Date 对象作为第一个参数传入,则只能传入 Date 本身或 date 的子类的第二个参数,这意味着第二个参数中的所有 Date 属性都将复制到第一个参数,没办法。如果我只允许两个任意对象,那么我可以传递 String 和 Date 并且复制没有任何意义。
猜你喜欢
  • 2010-09-18
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 2012-09-05
相关资源
最近更新 更多