何时/为何应该使用通用方法?

5

在学习Java时,我遇到了泛型方法

public <T> void foo(T variable) { }

这是一种采用未确定类型参数的方法(类似于PHP?)。然而,我无法看出这将是一个好的解决方案——特别是在从松散类型语言转换到强类型语言后,我已经爱上了强类型语言。

是否有使用通用方法的理由?如果有,什么时候使用?


看看java.util包,特别是泛型集合类,并与从Object转换的旧方法进行比较 :) - SirDarius
对于通用方法,请特别查看 java.util.Collections(是一个类名,带有“s”)。 - Tom Hawtin - tackline
1
仅作一点备注:泛型方法仍然是强类型的,只是类型由类型参数决定。例如, public <T> T foo(T variable) { } 总是返回相同类型的对象,而不是 任何 类型的对象。 - Goran Jovic
4个回答

4
那些曾经使用Java 5之前版本的人都知道,在将对象存储在集合中并在使用前将其强制转换为正确类型之前,这是多么不方便。泛型可以避免这种情况。它提供了编译时类型安全,并确保您仅向集合中插入正确的类型,并避免运行时出现ClassCastException。
因此,它提供了编译时类型安全和强制转换。当您想要编写具有复杂方法签名的复杂API时,它将在编写API和使用API时节省大量时间,并防止编写大量用于强制转换部分的代码以及在编译时捕获错误。只需查看java.util.Collection 包并查看源代码即可。
作为开发人员,我总是希望编译器在编译时捕获我的错误并在我想要编译它时通知我,然后我会修复我的错误,在运行时不会出现许多与类型安全相关的错误。
更多信息请参见:

我们这些来自C#世界的人在没有泛型的时代也有同样的痛苦 :) 编写类型安全的集合是一件非常麻烦的事情。 - David W
是的,绝对没错;但是C#和Java泛型之间有所不同,Java具有类型擦除,它将在编译后删除所有泛型并添加转换,因此我们无法通过反射在运行时访问泛型信息,例如,在这种情况下,List<T>List在运行时没有任何区别,但是C#不会在编译时删除这些信息,您可以在运行时访问泛型信息,并且在C#中List<T>List不同,如果您想编写支持通用和非通用用例的API,则应该将这些API编写两次。 - Mehdi

3

泛型(Generics)是一种提供模板的方法,例如你想要做相同的事情,唯一不同之处就在于类型。

例如,看一下List API,你会看到方法

add(E e)

对于每个声明的相同类型的列表,add方法唯一不同的地方就在于添加到列表中的元素的类型。这是泛型非常有用的一个典型例子。(在Java引入泛型之前,你可以声明一个列表,你可以向列表中添加任何东西,但是当你检索它时,你必须对对象进行强制转换)

更具体地说,你可能想要两个ArrayList实例,一个接受类型1,一个接受类型2。由于这两个列表都是ArrayList实例,add方法的列表代码将为每个列表执行相同的操作和代码,对吧?所以唯一不同的就是列表中的内容。

(正如@michael指出的那样,add不是真正的泛型方法的例子,但是链接的API中有真正的泛型方法,概念是相同的)


没错,但是列表 API 中有真正的通用函数,而且总体思路也是一样的。 - hvgotcodes

1

一般而言,泛型函数并没有非强类型的特点。类型在编译时被解析和检查。它不是一个未决定的类型,而是一系列可能的类型之一(在您的示例中可以受到限制)。在编译时,它是已知和确定的。

正如hvgotcodes所说,集合API包含了许多这种用法的好例子。


0
Generic概念的主要目标是:
  • 为集合提供类型安全,以便它们只能容纳一种特定类型的对象。
  • 解决强制转换问题。

要只保留String类型的对象,可以声明ArrayList的泛型版本如下:

ArrayList l = new ArrayList ();

了解更多信息:http://algovalley.com/java/generics.php


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接