关于泛型
什么是泛型?
泛型能让数据变得更严格 更不容易出错
这么说有点片面 下面用例子来说明:
Arraylist:动态数组,长度可变的数组。
Arraylist numbers = new Arraylist();
numbers.add(1);
numbers.add(2);
numbers.add("String")
numbers.forEach(System.out::println);
这里,可以看到我们插入了三个数据,但是第三个数据是一个String类型。
但是这样显然不合理,一个数组怎么会有整形又有字符串呢?
但是!让我用泛型来解决这个问题:
Arraylist<Integer> numbers = new Arraylist<>();
numbers.add(1);
numbers.add(2);
numbers.add("String")
numbers.forEach(System.out::println);
这时,可以看到我们在Arraylist后面加了,这就是泛型的应用。
它给数组规定了类型,当我们再往数组里插入String类型的数据时,程序就会报错。
这就是泛型的优点之一 让数据变得更加严格 更不容易出错!
泛型类
有什么用呢?
当然有用了,它既然是个类型,就可以声明变量。
private E first; //这里的E就是first的类型。
接下来我们用一串代码来做示范:
public class Pair<T> {
/* Pair类引入了一个类型变量T,用尖括号括了起来。
* 泛类型可以有多个类型变量。例如 可以定义Pria类,
*/其中 第一个域和第二个域使用不同的类型 Pair<T,F,V....>
private T first; //创建了两个变量
private T two;
//此处省略 带参、无参构造器、get、set方法
}
再创建一个类
class ArrayAlg{ //用来写一个方法
public static Pair<String> minmax(String[] a){ //调用泛型类来创造一个方法 用来比较字符串的大小
//注意,这时Prai<>这个尖括号中 就已经规定类型了 为String
if (a == null || a.length == 0) return null; //若数组的长度为0直接返回空
String min,max;
min = 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); //返回值的泛型语法,这时尖括号中已经不用再次写类型了。
}
}
接下来 测试一下:
public class PairTest {
public static void main(String[] args) {
String[] words = {"Mary","Litter","Ben","asfas","AFASafs"}; //给出一个数组
Pair<String> mm = ArrayAlg.minmax(words); // 把数组参数送到方法中 进行比较
System.out.printf("%s $s",mm.getFirst(),mm.getTwo());
}
}
这时,大概就知道泛型的好处了,为什么这么说?
因为如果我还要做一个方法,用来比较另外一组数据,我可以在最上面的类中加入另一个
变量类型 例如:Pair
泛型方法
值得一提的是 和抽象类还有抽象方法不一样
泛型类和泛型方法没有联系 上面例子中的方法 只是一个普通的方法
泛型方法主要提供了一种操纵数据的方法 就好比要取一个数组中好多元素的中间的那个,如果没有泛型,就要重载好多方法。
再用代码来解释:
public static <T> T getMiddle(T...a){ //泛型方法的写法<T>
return a[a.length/2];
}
注意这里我们并没有给这个方法的参数规定类型,下面,我们调用这个方法试一试:
System.out.println(ArrayAlg.getMiddle("asda","dasd","sadasd");
System.out.println(ArrayAlg.getMiddle("1","2","3");
还可以举很多例子,各种类型都可以。那么泛型方法的有点在哪呢?
如果我们不适用泛型:
public static int T getMiddle(int...a){ //泛型方法的写法<T>
return a[a.length/2];
}
System.out.println(ArrayAlg.getMiddle("1","2","3");
//可以看到,这个方法只能用int类型的数据。
public static int String getMiddle(String...a){ //泛型方法的写法<T>
return a[a.length/2];
}
System.out.println(ArrayAlg.getMiddle("asda","dasd","sadasd");
而这个方法只能用String类型的数据
每当你想用不同类型的数据去参与运算,你就得不停的去重载方法。非常麻烦!
类型变量的限定
有时,类或方法需要对类型变量加以约束,下面的例子中,我们要计算数组中的最小元素
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;
}
你会发现,当你写到第五行的时候 就会报错,因为compareTo方法必须
是在有comparebo接口的情况下才能使用的。
那要怎么办呢?
答:让继承comparebo接口!!!
下面正确代码:
public static <T extends & Comparable> 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;
}
这样就可以了。
关于类型变量的限定 需要注意以下几点:
1.泛类型可以继承多个接口,但是标记性接口一定要放在最后。
2.泛类型要继承类的时候,一定要让类放在最前面。
以上所学为个人总结。难免不严谨,见谅!