文章目录
- 第一节 泛型入门
- 第二节 自定义泛型设计
- 第三节 泛型类型限定
- 第四节 泛型实现的本质和约束
- 第五节 java类型协变和逆变
- 总结
第一节 泛型入门
泛型是啥?泛型是JDK1.5推出的特性,指的是编写的代码可以被很多不同类型的对象重用。
用来解决啥问题?编程中,我们希望可以参数化类型,避免类型转换,实现代码复用性。
举个例子:通过指定类型(<>中的内容)
泛型分类:
- 泛型类:ArrayList、HashSet、HashMap等
- 泛型方法:Collections.binarySearch、Arrays.sort等
- 泛型接口:List、Iterator等
第二节 自定义泛型设计
希望自己能够设计泛型类,泛型方法、泛型接口。
泛型类定义:
- 具有泛型变量的类。在类名后面用代表引用类型。
- 多个字母表示多个引用类型,如<T,U>等。
- 引用类型可以修饰成员变量、局部变量、参数和返回值。
泛型类使用:
interval<Integer> v1 = new Interval<Integer>(1,2);
泛型方法:
- 具有泛型参数的方法,可以存在与普通类和泛型类中。
- 在修饰符后,返回类型前
- 调用泛型方法时,引用类型时需要一致,否则容易出错。
public class ArrayUtil {
public static void main(String[] args) {
String s1 = Test.<String>getMiddle("abc","def","ghi");
Integer i1 = Test.getMiddle(1,2,3);
//null is ok
String s2 = Test.getMiddle("abc",null,null);
Number i2 = Test.getMiddle(1,2.5f,2.5f);
System.out.println(s1); //def
System.out.println(i1); //2
System.out.println(s2); //null
System.out.println(i2); //2.5
}
}
class Test{
public static <T> T getMiddle(T... a) {
return a[a.length/2];
}
}
泛型接口:
- 和泛型类相似,在类名后加
- T用来指定方法返回值和参数
- 实现接口时,指定类型,实现类不要求是泛型类,可以把其当做普通类。
- 类型是可以相互嵌套的
类型嵌套实例:
第三节 泛型类型限定
泛型的限定:希望在某些场合下,对泛型的类型进行限定,要求传入的类型必须有啥方法、实现啥接口。
package chapter8;
import java.time.*;
public class PareTest2 {
public static void main(String[] args) {
LocalDate[] birthdays = {
LocalDate.of(1906, 12, 9),
LocalDate.of(1815, 12, 10),
LocalDate.of(1910, 12, 3),
LocalDate.of(1910, 6, 23),
};
Pair<LocalDate> mm = ArrayAlg2.minmax(birthdays);
System.out.println(mm.getFirst());
System.out.println(mm.getSecond());
}
}
class ArrayAlg2{
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 = 0; 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);
}
}
泛型类之间的继承:
-
Pair<S>
和Pair<T>
没有任何关系,无论S和T之间是啥关系。 - 泛型类可以扩展或者实现其他类,如
ArrayList<T>
实现List<T>
。
上面两句话是啥意思呢?意思是泛型类之间的继承与T无关,与类本身的继承相关联。
泛型中通配符的使用。
通配符限定与类型变量限定十分类似,但是,可以指定一个超类型限定。
直观讲:带有超类型限定的通配符运行写入一个泛型对象,带有子类型限定的通配符允许读入一个泛型对象。
下面这段代码就能够体现这个原则。
package chapter8;
import inherit.Employee;
import inherit.Manager;
public class PairTest3 {
public static void main(String[] args) {
var ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
var cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
var buddies = new Pair<Manager>(ceo, cfo);
ceo.setBonus(1000000);
cfo.setBonus(500000);
Manager[] managers = {ceo, cfo};
var result = new Pair<Employee>();
minmaxBonus(managers, result);
System.out.println("first: " + result.getFirst().getName() + " , second: " + result.getSecond().getName());
maxminBonus(managers, result);
System.out.println("first: " + result.getFirst().getName() + " , second: " + result.getSecond().getName());
}
public static void printBuddies(Pair<? extends Employee> p) {
Employee first = p.getFirst();
Employee second = p.getSecond();
System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
}
public static void minmaxBonus(Manager[] a, Pair<? super Manager> result) {
if(a.length == 0) return;
Manager min = a[0];
Manager max = a[0];
for(int i = 0; i < a.length; i++) {
if(min.getBonus() > a[i].getBonus()) min = a[i];
if(max.getBonus() < a[i].getBonus()) max = a[i];
}
result.setFirst(min);
result.setSecond(max);
}
public static void maxminBonus(Manager[] a, Pair<? super Manager> result) {
minmaxBonus(a, result);
PairAlg3.swap(result);
}
}
class PairAlg3{
public static boolean hasNulls(Pair<?> p) {
return p.getFirst() == null || p.getSecond() == null;
}
public static void swap(Pair<?> p) {
swapHelper(p);
}
public static <T> void swapHelper(Pair<T> p) {
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}
第四节 泛型实现的本质和约束
这个类型擦除才能够很好的解释泛型的特点与本质。
第五节 java类型协变和逆变
总结
坚持走下去。