一.概述
上一篇学习了泛型的基本使用和一些限制,这篇继续上一次没有学完的一些内容。Java泛型(一)
注意当类型参数存在继承关系的时候,同样类型之间不存在继承关系。Pair<Emploee>和Pair<Manager>
并不存在继承关系。但是List<String>和ArrayList<String>
是存在继承关系的。
二.通配符类型
1.通配符子类型限定
上一节学习其实已经涉及到通配符的使用了,例如:Pair<? extends Emploee>
但是这样会有一个问题当使用set方法的时候是报告类型错误,因为set(Pair<? extends Emploee> p) 方法只知道参数是Emploee的一个自类型,但是具体的子类型是无法确定的,但是get获取到的返回值是可以赋值给Emploee的,虽然不知道具体类型,但是可以确定是Emploee的子类型。
2.通配符超类型限定
和通配符子类型限定很相像。Pair<? super Manage>
表示限定为Manger的超类。
但不同的是它可以作为set方法的参数因为可以确定的是只要是Manager类型的父类就可以传入,但是get方法就不行了,因为无法确定是Manger父类的具体类型。
通过前两点可以总结为:带有超类型限定的通配符可以向泛型对象写入 ,带有子类型限定的通配符可以从泛型对象读取。
3.无限定通配符
无限定就是类型参数只用?代表。Pair<?>
表示无限定通配符。
看起来和Pair类型一样,但还是有很大的区别的,它里面存在两个方法:
? getFirst()
void setFirst(?)
这样get方法只能接收Object类型的变量,而不是任意对象。set的方法无法调用,由于无法确定具体类型。
4.通配符的捕获
通配符捕获只有在许多限制的情况下才是合法的。编译器必须能够确信通配符表达的是单个、确定的类型。
import com.gyx.demo.chapter6.Employee;
import com.gyx.demo.chapter6.Manager;
/**
* 通配符实例
*/
public class PairDemo {
public static void main(String[] args) {
Manager ceo = new Manager("a",2000);
Manager cfo = new Manager("b",500);
Pair<Manager> buddies = new Pair<>(ceo,cfo);
printBuddies(buddies);
ceo.setBonus(3000);
cfo.setBonus(2000);
Manager[] managers = {ceo,cfo};
Pair<Employee> result = new Pair<>();
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());
}
/**
* 这个方法如果传入Pair<Manager>类型就会报错
* 可以使用通配符来解除这一个限制
* 将Pair<Employee>换成Pair<? extends Employee>这样是Employee的子类都可以传递了
*/
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.");
}
/**
* 通配符超类型限定
* @param a
* @param result
*/
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);
//
PairAlg.swapHelper(result);
}
}
class PairAlg {
/**
* 无限定通配符的作用
* 它可以用来判断一个类型是否含有null引用。
* @param p
* @return
*/
public static boolean hasNulls(Pair<?> p) {
return p.getFirst() == null || p.getSecond() == null;
}
/**
* 因为不能使用?号作为类型定义,但交换的时候还需要保存第一个元素。
* @param p
*/
public static void swap(Pair<?> p) {
swapHelper(p);
}
/**
* 编写一个辅助方法,它与swap方法的区别是:
* 它是一个泛型方法,但是swap不是,它是一个具有固定的Pair<?>类型的参数
* 这样可以使用T来捕获?的通配符参数类型
* @param p
* @param <T>
*/
public static <T> void swapHelper(Pair<T> p) {
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}
三.反射和泛型
列举一个书中的实例查询出类中的所有泛型方法,具体方法可以自行查询API来查询一下。
import java.lang.reflect.*;
import java.util.*;
/**
* 反射与泛型实例
* 查询出泛型类中所有的泛型方法
*/
public class GenericReflectionDemo {
public static void main(String[] args) {
String name;
if (args.length > 0) {
name = args[0];
} else {
try (Scanner in = new Scanner(System.in)) {
System.out.println("Enter class name (e.g java.util.Collections): ");
name = in.next();
}
}
try {
Class<?> cl = Class.forName(name);
printClass(cl);
for (Method method : cl.getDeclaredMethods()) {
printMethod(method);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void printClass(Class<?> cl) {
System.out.print(cl);
printTypes(cl.getTypeParameters(), "<", ", ", ">", true);
Type sc = cl.getGenericSuperclass();
if (sc != null) {
System.out.print(" extends ");
printType(sc, false);
}
printTypes(cl.getGenericInterfaces(), " implements ", ", ", "", false);
System.out.println();
}
public static void printMethod(Method m) {
String name = m.getName();
System.out.print(Modifier.toString(m.getModifiers()));
System.out.print(" ");
printTypes(m.getTypeParameters(), "<",", ",">",true);
printType(m.getGenericReturnType(),false);
System.out.print(" ");
System.out.print(name);
System.out.print("(");
printTypes(m.getGenericParameterTypes(),"",", ","",false);
System.out.println(")");
}
public static void printTypes(Type[] types, String pre, String sep, String suf, boolean isDefinition) {
if (" extends ".equals(pre) && Arrays.equals(types, new Type[]{Object.class})) {
return;
}
if (types.length > 0) {
System.out.print(pre);
}
for (int i = 0; i < types.length; i++) {
if (i > 0) {
System.out.print(sep);
}
printType(types[i], isDefinition);
}
if (types.length > 0) {
System.out.print(suf);
}
}
public static void printType(Type type, boolean isDefinition) {
if (type instanceof Class) {
Class<?> t = (Class<?>) type;
System.out.print(t.getName());
} else if (type instanceof TypeVariable) {
// 描述类型变量
TypeVariable<?> t = (TypeVariable<?>) type;
System.out.print(t.getName());
if (isDefinition) {
printTypes(t.getBounds(), " extends ", " & ", "", false);
}
} else if (type instanceof WildcardType) {
// 描述通配符
WildcardType t = (WildcardType) type;
System.out.print("?");
printTypes(t.getUpperBounds(), " extents ", " & ", "", false);
printTypes(t.getLowerBounds(), " super ", " & ", "", false);
} else if (type instanceof ParameterizedType) {
// 描述泛型类或接口类型
ParameterizedType t = (ParameterizedType) type;
Type owner = t.getOwnerType();
if (owner != null) {
printType(owner, false);
System.out.print(".");
}
printType(t.getRawType(), false);
printTypes(t.getActualTypeArguments(), "<", ", ", ">", false);
} else if (type instanceof GenericArrayType) {
// 描述泛型数组
GenericArrayType t = (GenericArrayType) type;
System.out.print("");
printType(t.getGenericComponentType(), isDefinition);
System.out.print("[]");
}
}
}
四.总结
这两节说的都比较笼统,只是说了一些基本使用,和一些限制,高级用法说的基本也都是书中讲解的,再加上一些个人的理解在里面。等以后确实用到比较多的时候,或者又一些更高的感悟的时候也会回来修改的。
下一篇学习泛型使用最多的集合类,这部分会分成好几篇来学习,内容比较多,花费时间也比较多,当然还是以基本使用为主,原理性的东西也会涉及到一点点。
有些可能我理解的不够深刻,大家如果觉得我说的不够详细可以参考我的推荐书,详细的看一下。欢迎大家评论。第一时间我会回复大家。谢谢!