1. 泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型的边界来约束👉。
1.1 语法🌵
class 泛型类名称<类型形参 extends 类型边界>{
...
}
//示例:
public class MyArray<E extends Number>{
...
}
【示例一】
class TestGeneric<T extends Number>{
//继承于Number类
}
public class Test {
public static void main(String[] args) {
//指明类型是Number
TestGeneric<Number> testGeneric = new TestGeneric<>();
//指明类型是Integer
TestGeneric<Integer> testGeneric1 = new TestGeneric<>();
//指明类型是Double
TestGeneric<Double> testGeneric2 = new TestGeneric<>();
//指明类型是String,但是这里会编译报错,因为上面的Integer和Double都是Number的子类,但是String不是Number的子类
TestGeneric<String> testGeneric3 = new TestGeneric<>();
}
}
1.2 实例应用🐣
要求写一个泛型类,可以求一个数组的最大值。
思考: 如果涉及到比较的话,那我们就需要考虑到,泛型中的T一定要是可以比较的,那我们如何实现这个想法呢? |
- 这里我们采用的策略是,可以让T实现Comparable接口,如果一个类实现了Comparable接口,就意味着这个类👉支持排序。
【代码】
//T实现了Comparable接口
class Alg<T extends Comparable<T>>{
//找出数组中的最大值并返回 参数是数组
public T findMaxValue(T[] array){
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (max.compareTo(array[i]) < 0){
max = array[i];
}
}
return max;
}
public static void main(String[] args) {
Alg<Integer> alg = new Alg<>();
Integer[] array = {2, 10, 5, 7, 9};
Integer max = alg.findMaxValue(array);
System.out.println(max);
}
}
代码详细解释见下图:
1.3 泛型方法🐢
上面我们写的是一个泛型类,那如果现在要求发生了变化,要求我们用一个泛型方法,来找出数组中的最大值,写法会不会有很大的变化呢?
【代码】
class Alg2{
//泛型方法
public<T extends Comparable<T>> T findMaxValue(T[] array){
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (max.compareTo(array[i]) < 0){
max = array[i];
}
}
return max;
}
public static void main(String[] args) {
Alg2 alg2 = new Alg2();
Integer[] array = {1, 2, 4, 7, 87, 90};
Integer max = alg2.findMaxValue(array);
System.out.println(max);
}
}
我们可以看到,这个方法的方法头看着好像比之前要更复杂一些,方法体倒是没什么变化,好像就是把之前写在类后面的代码,现在写在了方法头这里。
【注意🙈】
其实这里的逻辑,是发生了类型推导,虽然我们在创建对象的时候,没有直接标明类型,但在运行的时候,会根据我们传递给方法的值,来推导出类型。
上面我们了解了泛型的上界,我们还需要知道的一点是,泛型没有下界。