【java基础(五十二)】泛型方法和类型变量的限定

泛型方法

前面已经介绍了如何定义一个泛型类。实际上,还可以定义一个带有类型参数的简单方法。

class ArrayAlg {
	public static <T> T getMiddle(T... a) {
		return a[a.length / 2];
	}
}

这个方法是在普通类中定义的,而不是在泛型类中定义的。然而,这是一个泛型方法,可以从尖括号和类型变量看出这一点。注意,类型变量放在修饰符的后面,返回类型的前面。

泛型方法可以定义在普通类中,也可以定义在泛型类中。

当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:

String middle = ArrayAlg.<String>getMiddle("John", "Q", "PUblic");

在这种情况下,方法调用中可以省略<String>类型参数。编译器有足够的信息能够推断出所调用的方法。它用names的类型与泛型类型进行匹配并推断出T一定是String。也就是说,可以调用:

String middle = ArrayAlg.getMiddle("John", "Q", "PUblic");

几乎在大多数情况下,对于泛型方法的类型引用没有问题。偶尔,编译器也会提示错误,此时需要解释错误报告。如:

double middle = ArrayAlg.getMiddle(3.14, 1729, 0);

错误消息会以晦涩的方式指出(不同的编译器给出的错误消息可能有所不同):解释这句代码有两种方法,而且这两种方法都是合法的。简单地说,编译器将会自动打包参数为1个Double和2个Integer对象,而后寻找这些类的共同超类型。事实上,找到2个这样的超类型:Number和Comparable接口,其本身也是一个泛型类型。在这种情况下,可以财局的补救措施是将所有的参数写为double值。

类型变量的限定

有时,类或方法需要对类型变量加以约束。下面是一个典型的例子。我们要计算数组中的最小元素:

class ArrayAlg {
	public static <T> T min(T[] a) {
		if (a == null || a.length == 0) return null;
		T smallest = a[0];
		for (int i = 1; i < a.length; i++)
			if (smallest.compareTo(a[i]) > 0) smallest = a[i];

		return smallest;
	}
}

但是,这里有一个问题。请看一下min方法的代码内部。变量smallest类型为T,这意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?

解决这个问题的方案是将T限制为实现了Comparable接口的类。可以通过对类型变量T设置限定(bound)实现这一点:

public static <T extends Comparable> T min(T[] a) ...

实际上Comparable接口本身就是一个泛型类型。目前,我们忽略其复杂性以及编译器产生的警告。

现在,泛型的min方法只能被实现了Comparable接口的类(如String、LocalDate等)的数组调用。

或许你会感到奇怪,在此为什么使用关键字extends而不是implements?毕竟,Comparable是一个接口。

<T extends BoundingType>

表示T应该是绑定类型的子类型(subtype)。T和绑定类型可以是类,也可以是接口。选择关键字extends的原因是更接近子类的概念,并且Java的设计者也不打算在语言中再添加一个新的关键字。

一个类型变量或通配符可以有多个限定,如:

T extends Comparable & Serializable

限定类型用“&”分割,而逗号用来分割类型变量。

在Java的继承中,可以根据需要拥有多个接口超类型,但限定中至多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。

实例

PairTest2.java

package cn.freedompc.pair2;

import java.time.LocalDate;

import cn.freedompc.pair.Pair;

public class PairTest2 {

	public static void main(String[] args) {
		LocalDate[] birthdays = {
				LocalDate.of(1906, 12, 9),
				LocalDate.of(1815, 12, 10),
				LocalDate.of(1903, 12, 3),
				LocalDate.of(1910, 6, 22),	
		};
		Pair<LocalDate> mm = ArrayAlg.minmax(birthdays);
		System.out.println("min = " + mm.getFirst());
		System.out.println("max = " + mm.getSecond());
	}
	
}

class ArrayAlg {
	
	public static <T extends Comparable> Pair<T> minmax(T[] a) {
		if (a == null || a.length == 0) return null;
		T min = a[0];
		T max = a[0];
		for (int i = 1; i < a.length; i++) {
			if (min.compareTo(a[i]) > 0) min = a[i];
			if (max.compareTo(a[i]) < 0) max = a[i];
		}
		return new Pair<>(min, max);
	}
	
}

结果

在这里插入图片描述

捐赠

若你感觉读到这篇文章对你有启发,能引起你的思考。请不要吝啬你的钱包,你的任何打赏或者捐赠都是对我莫大的鼓励。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章