Java 如何写泛型方法
你有没有过这种经历:写代码的时候,明明想给一个工具类写个“通用”方法,结果为了适配不同类型,要么重复写好几套逻辑,要么被迫用 Object 类型,最后还要手动强转——转不对还容易报运行时错误?
比如你要写一个打印任意数组的方法,用 Object 类型的话,代码大概是这样:

public static void printArray(Object[] arr) {
for (Object o : arr) {
System.out.println(o);
}
}
但这个方法只能处理 Object 数组,要是你给它传 String 数组或者 Integer 数组,虽然编译能过,但 IDE 可能会飘黄警告,而且如果不小心传了 int 这种基本类型数组,直接就报错了。这时候 Java 的泛型方法就能帮你解决这个麻烦。
什么是泛型方法?
简单说,泛型方法就是把“类型参数”(相当于一个临时的类型占位符)放在方法的修饰符和返回值之间,就像给方法开了个“类型接口”,调用的时候才指定具体用什么类型。
还是拿刚才打印数组的例子,用泛型方法改写后,代码就变成了:
public static <T> void printArray(T[] arr) {
for (T item : arr) {
System.out.println(item);
}
}
这里的 <T> 就是类型参数,你可以把它理解成“随便什么类型”——调用的时候,你传 String 数组,T 就自动变成 String;传 Integer 数组,T 就自动变成 Integer,不用手动声明,编译器会自动识别,既不用重复写代码,也不用强转。
泛型方法的“类型边界”:别让“随便什么类型”乱套
有时候你不想让 T 是任意类型,比如想写一个方法,既能加数字又能做运算,这时候就需要给类型参数加“边界”,限制 T 的范围。比如要写一个计算数组元素总和的泛型方法,普通的 T 就不行了,因为你不能对任意类型做加法,这时候就要让 T 继承 Number 类,也就是:
public static <T extends Number> double sumArray(T[] arr) {
double sum = 0;
for (T num : arr) {
sum += num.doubleValue(); // 因为 T 是 Number 的子类,才有 doubleValue 方法
}
return sum;
}
这里的 T extends Number 就是类型边界,相当于告诉编译器:“T 必须是 Number 或它的子类,比如 Integer、Double 这些,这样才能调用 Number 里的方法”。如果传了 String 数组,编译器直接会报错,从根源上避免了类型错误。
泛型方法和普通方法的区别:别搞混“类泛型”和“方法泛型”
新手很容易把泛型方法和类里的泛型搞混。比如一个类如果声明了 <T>,那这个类里的所有非静态方法都可以直接用这个 T;但如果是泛型方法,它的 <T> 是自己独有的,只在这个方法里生效,和类里的泛型没关系。
举个生活化的例子:你开了一家“万能工具店”(对应泛型类),店里的所有工具都能适配不同尺寸(类泛型 T),但如果你单独做了一个“定制螺丝刀”(对应泛型方法),这个螺丝刀的适配尺寸是它自己定的,和店里其他工具没关系——这就是泛型方法的独立性,它可以让你在普通类里,只给需要的方法加通用能力,不用把整个类都改成泛型。
写泛型方法的小技巧
新手写泛型方法,最容易犯的错是把类型参数写得太随意,比如用 <T> 没问题,但别用和业务无关的符号,而且尽量给边界留够范围——如果不需要限制类型,就不用加 extends;如果需要多个边界,用 & 连接,比如 <T extends Number & Serializable>,表示 T 既要继承 Number,又要实现 Serializable 接口。
还有个小细节:泛型方法的类型参数必须放在返回值前面,不能放后面,比如 void <T> print(T t) 是对的,void print(T t) <T> 就会编译报错,记住这个顺序就不会踩坑。
说白了,泛型方法就是给 Java 方法加了“类型适配的灵活性”,既解决了重复代码的问题,又能在编译阶段就把类型错误拦下来,比用 Object 类型靠谱多了。下次遇到要写通用逻辑的时候,不妨试试给方法加个 <T>,说不定能省不少麻烦。