泛型的简单使用
1. 泛型一般用E表示集合中元素;k和v表示Map中的key和value;R表示return值;T/U/S表示任意类型
//(1) 简单单个元素的泛型
Box<String> boxString = new Box<>();
boxString.setT("boxString");
System.out.println(boxString.toString());
Box<Integer> boxInteger = new Box<>();
boxInteger.setT(888);
System.out.println(boxInteger.toString());
class Box<T> {
private T t;
public Box() {
t = null;
}
public Box(T t) {
this.t = t;
}
public static <T> Box<T> makeBox(Supplier<T> supplier) {
return new Box<>(supplier.get());
}
public static <T> Box<T> makeBox(Class<T> cl) {
try {
return new Box<>(cl.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance();
list.add(elem);
}
@Override
public String toString() {
return t+"";
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
//(2) 两个元素的泛型
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Pair.compare(p1, p2);
System.out.println("Pair.compare() same:"+same);
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());
}
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
//(3) 指定元素 T extends Comparable<T> 边界符
int countGreaterThan = countGreaterThan(new String[]{"111","222"}, "11");
System.out.println("countGreaterThan:"+countGreaterThan);
//可以指定绑定多个限定 T extends Comparable<T>&Serializable
countGreaterThan = countGreaterThan2(new String[]{"111","222"}, "11");
System.out.println("countGreaterThan:"+countGreaterThan);
//多个泛型带绑定 T extends Comparable<T>&Serializable, U extends T
countGreaterThan = countGreaterThan3(new String[]{"111","222"}, "11");
System.out.println("countGreaterThan:"+countGreaterThan);
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0) {
++count;
}
return count;
}
public static <T extends Comparable<T>&Serializable> int countGreaterThan2(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0) {
++count;
}
return count;
}
public static <T extends Comparable<T>&Serializable, U extends T> int countGreaterThan3(T[] anArray, U elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0) {
++count;
}
return count;
}
//(4) 指定通配元素 ? 边界符
// <? extends A> 表示 T必须是A的子类
// <? super A> 表示T必须是A的父类
// <?>无限定通配符
//1) ? extends T 可以加 T本身和T的子类 均可以get()
//实现了<? extends T>的集合类只能将它视为Producer向外提供(get)元素,而不能作为Consumer来对外获取(add)元素
List<Apple> apples = Arrays.asList(new Apple());
List<Orange> oranges = Arrays.asList(new Orange());
List<Fruit> fruit = Arrays.asList(new Fruit());
Covariant<Fruit> fruitReader = new Covariant<Fruit>(); //指定通配符 T为Fruit, readCovariant() list元素 extends Fruit
Fruit f = fruitReader.readCovariant(fruit);
Fruit a = fruitReader.readCovariant(apples);
Fruit o = fruitReader.readCovariant(oranges);
System.out.println(f.toString());
System.out.println(a.toString());
System.out.println(o.toString());
//2) ? super T
//要add元素应该怎么做呢?可以使用<? super T> T本身和T的子类 均可以add(), 注意T的类型
fruit = new ArrayList<Fruit>();
Covariant.writeWithWildcard(fruit, new Apple());
Covariant.writeWithWildcard(fruit, new Orange());
Covariant.writeWithWildcard(fruit, new Fruit());
System.out.println("writeWithWildcard size"+fruit.size());
//总结出一条规律,”Producer Extends, Consumer Super”:
//“Producer Extends” - 如果你需要一个只读List,用它来produce T,那么使用? extends T。
//“Consumer Super” - 如果你需要一个只写List,用它来consume T,那么使用? super T。
//如果需要同时读取以及写入,那么我们就不能使用通配符了。
//3) 结合使用
Covariant.copy(apples, fruit);
Covariant.copy(oranges, fruit);
System.out.println("copy size"+fruit.size());
System.out.println();
class Fruit {
}
class Apple extends Fruit {
}
class Orange extends Fruit {
}
static class Covariant<T> {
T readCovariant(List<? extends T> list) {
return list.get(0);
}
static <T> void writeWithWildcard(List<? super T> list, T item) {
list.add(item);
}
public static <T> void copy(List<? extends T> source, List<? super T> dest) {
for (int i=0; i<source.size(); i++)
dest.set(i, source.get(i));
}
}
无边界通配符 ?
通配符的意义就是它是一个未知的符号,可以是代表任意的类。
泛型变量T不能在代码用于创建变量,只能在类,接口,函数中声明以后,才能使用。
无边界通配符?则只能用于填充泛型变量T,表示通配任何类型!!!!
只能出现在声明位置,不能出现在实现位置
Box<?> box;
box = new Box<String>();
<? extends XXX>指填充为派生于XXX的任意子类的话
<? super XXX>则表示填充为任意XXX的父类!
extends通配符,能取不能存
super通配符:能存不能取
通配符?总结
总结 ? extends 和 the ? super 通配符的特征,我们可以得出以下结论:
◆ 如果你想从一个数据类型里获取数据,使用 ? extends 通配符(能取不能存)
◆ 如果你想把对象写入一个数据结构里,使用 ? super 通配符(能存不能取)
◆ 如果你既想存,又想取,那就别用通配符。
构造泛型实例时,如果省略了填充类型,则默认填充为无边界通配符!
http://blog.csdn.net/harvic880925/article/details/49883589
泛型类
class InfoImpl<T> implements Info<String>{
…………
}
非泛型类
class InfoImpl implements Info<String>{
…………
}
两种泛型传参方法
class StaticFans {
//静态函数
public static <T> void StaticMethod(T a){
System.out.println("harvic StaticMethod: "+a.toString());
}
//普通函数
public <T> void OtherMethod(T a){
System.out.println("harvic OtherMethod: "+a.toString());
}
}
//4) 使用方法
//静态方法
StaticFans.StaticMethod("adfdsa");//使用方法一 , 类型没有限制
StaticFans.<String>StaticMethod("adfdsa");//使用方法二 , 限制了String
//常规方法
StaticFans staticFans = new StaticFans();
staticFans.OtherMethod(new Integer(123));//使用方法一 , 类型没有限制
staticFans.<Integer>OtherMethod(new Integer(123));//使用方法二 , 限制了String
// IntFunction 返回R必须是数组?
public static <T> T[] getTArray(IntFunction<T[]> fun, int value) {
T[] apply = fun.apply(value);
return apply;
}
@SuppressWarnings("unchecked")
public static <T> T[] getTArray(T... values) {
return (T[]) Array.newInstance(values.getClass().getComponentType(), values.length);
}
@SuppressWarnings("unchecked")
public static <T> T[] getTArray2(T... values) {
return values;
}
instanceof
2.instanceof只能用来查看原始的类,不能用来查看带泛型的比如ArrayList<String>
无法对泛型代码直接使用instanceof关键字,因为Java编译器在生成代码的时候会擦除所有相关泛型的类型信息
ArrayList<String> arrayString = new ArrayList<>();
ArrayList<Integer> arrayInteger = new ArrayList<>();
System.out.println(arrayString instanceof ArrayList);
System.out.println(arrayInteger instanceof ArrayList);
System.out.println();
类型擦除 带来的问题
// 3.不能new泛型 new T()
//还可以采用Factory和Template两种设计模式解决,感兴趣的朋友不妨去看一下Thinking in Java中第15章中关于Creating instance of types(英文版第664页)的讲解,这里我们就不深入了
// 方式一,提高Supplier<T>接口, 无参数传入,返回类型为T
Box<String> makePair = Box.makeBox(String::new);
System.out.println(makePair.getT());
// 方式二,传入class, class本身是泛型的
makePair = Box.makeBox(String.class);
System.out.println(makePair.getT());
List<String> arrayList = new ArrayList<>();
Box.append(arrayList, String.class);
// 4.不能new泛型数组
//运行时期类型信息已经被擦除,JVM实际上根本就不知道数组里面元素的区别
// 5.不能构造泛型数组
// 方式一,利用IntFunction,
String[] tArray = getTArray(String[]::new, 2);
System.out.println(tArray.length);
// 方式二,利用反射
String[] tArray2 = getTArray("", "", "");
System.out.println(tArray2.length);
泛型相关
1)Type
Class类中泛型相关
public Type getGenericSuperclass();
public Type[] getGenericInterfaces();
Type的五种类型
- Class
- ParameterizedType:代表的是一个泛型类型,比如Point;
- TypeVariable:这个代表的就是泛型变量,例如Point,这里面的T就是泛型变量,而如果我们利用一种方法获得的对象是T,那它对应的类型就是TypeVariable;
- WildcardType:通配符比如:? extends Integer,那它对应的类型就是WildcardType;
- GenericArrayType:如果我们得到的是类似String[]这种数组形式的表达式,那它对应的类型就是GenericArrayType,非常值得注意的是如果type对应的是表达式是ArrayList这种的,这个type类型应该是ParameterizedType,而不是GenericArrayType,只有类似Integer[]这种的才是GenericArrayType类型。
2)getGenericSuperclass()
class Point<T> {
private T x,y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
//PointImpl类的实现
class PointImpl extends Point<Integer> {
}
Class<?> clazz = PointImpl.class;
Type genericSuperclassType = clazz.getGenericSuperclass();
if(genericSuperclassType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclassType;
//返回表示此类型实际类型参数的 Type 对象的数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type parameterArgType : actualTypeArguments) {
Class parameterArgClass = (Class) parameterArgType;
System.out.println("填充类型为:" + parameterArgClass.getName());
}
//返回 Type 对象,表示声明此类型的类或接口。
Type type1 = parameterizedType.getRawType();
Class class22 = (Class) type1;
System.out.println("PointImpl的父类类型为:"+class22.getName());
}
填充类型为:java.lang.Integer
PointImpl的父类类型为:t.Point
3)getGenericInterfaces()
class Point<T> {
private T x,y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
interface PointInterface<T,U> {
}
class PointImpl extends Point<Integer> implements PointInterface<String,Double> {
}
Class<?> clazz = PointImpl.class;
Type[] genericInterfaces = clazz.getGenericInterfaces();
for (Type genericSuperclassType : genericInterfaces) {
if(genericSuperclassType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclassType;
//返回表示此类型实际类型参数的 Type 对象的数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type parameterArgType : actualTypeArguments) {
Class parameterArgClass = (Class) parameterArgType;
System.out.println("填充类型为:" + parameterArgClass.getName());
}
//返回 Type 对象,表示声明此类型的类或接口。
Type type1 = parameterizedType.getRawType();
Class class22 = (Class) type1;
System.out.println("PointImpl的父类类型为:"+class22.getName());
}
}
填充类型为:java.lang.String
填充类型为:java.lang.Double
PointImpl的父类类型为:t.PointInterface
4)ParameterizedType
- getActualTypeArguments():用来返回当前泛型表达式中,用来填充泛型变量的真正值的列表。像我们这里得到的Point,用来填充泛型变量T的是Integer类型,所以这里返回的Integer类型所对应的Class对象。(有关这一段,下面会补充,这里先看getRawType)
- getRawType():我们从我们上面的代码中,也可以看到,它返回的值是Point,所以它的意义就是声明当前泛型表达式的类或者接口的Class对象。比如,我们这里的type对应的是Point,而声明Point这个泛型的当然是Point类型。所以返回的是Point.Class
5)TypeVariable
type代表的类型是一个泛型变量时,它的类型就是TypeVariable。TypeVariable有两个函数
- getName:就是得到当前泛型变量的名称;
- getBounds:返回表示此类型变量上边界的 Type 对象的数组。如果没有上边界,则默认返回Object;
interface TypeVariablePointInterface<T, U> {
}
class TypeVariableointGenericityImpl<T extends Number & Serializable> implements TypeVariablePointInterface<T, Integer> {
}
Class<?> clazz = TypeVariableointGenericityImpl.class;
Type[] types = clazz.getGenericInterfaces();
for (Type type : types) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// 返回表示此类型实际类型参数的 Type 对象的数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type parameterArgType : actualTypeArguments) {
if (parameterArgType instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) parameterArgType;
System.out.println("此接口的填充类型为:" + typeVariable.getName());
// 返回表示此类型变量上边界的 Type 对象的数组。
Type[] typebounds = typeVariable.getBounds();
for (Type bound : typebounds) {
Class<?> boundClass = (Class) bound;
// 如果不写,则默认输出Object,如果写了,则输出对应的
System.out.println("bound为:" + boundClass.getName());
}
}
if (parameterArgType instanceof Class) {
Class parameterArgClass = (Class) parameterArgType;
System.out.println("此接口的填充类型为:" + parameterArgClass.getName());
}
}
}
}
此接口的填充类型为:T
bound为:java.lang.Number
bound为:java.io.Serializable
此接口的填充类型为:java.lang.Integer
6)WildcardType
当type所代表的表达式是类型通配符相关的表达式时,比如<? extends Integer>,<? super String>,或者<?>等,这个type的类型就是WildcardType!
我们先来看看WildcardType的函数:
- getUpperBounds:获取上边界对象列表,上边界就是使用extends关键定所做的的限定,如果没有默认是Object;
- getLowerBounds:获取下边界对象列表,下边界是指使用super关键字所做的限定,如果没有,则为Null
<? extends Integer>:这个通配符的上边界就是Integer.Class,下边界就是null
<? super String>:这个通配符的下边界是String,上边界就是Object;
通配符只能用来填充泛型类来生成对象
interface PointSingleInterface<T> {
}
class PointWildcardImpl implements PointSingleInterface<Comparable<? extends Number>> {
}
Class<?> clazz = PointWildcardImpl.class;
// 此时的type对应PointSingleInterface<Comparable<? extends Number>>
Type[] types = clazz.getGenericInterfaces();
for (Type type : types) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// 得到填充PointSingleInterface的具体参数,即:Comparable<? extends Number>,仍然是一个ParameterizedType
Type[] actualTypes = parameterizedType.getActualTypeArguments();
for (Type actualType : actualTypes) {
if (actualType instanceof ParameterizedType) {
ParameterizedType ComparableType = (ParameterizedType) actualType;
// 对Comparable<? extends Number>再取填充参数,得到的type对应<? extends Number>,这个就是WildcardType了
Type[] compareArgs = ComparableType.getActualTypeArguments();
for (Type Arg : compareArgs) {
if (Arg instanceof WildcardType) {
// 将得到的对应WildcardType的type强转为WildcardType的变量
WildcardType wt = (WildcardType) Arg;
// 利用getLowerBounds得到下界,即派生自Super的限定,如果没有派生自super则为null
Type[] lowerBounds = wt.getLowerBounds();
for (Type bound : lowerBounds) {
Class<?> boundClass = (Class) bound;
System.out.println("lowerBound为:" + boundClass.getName());
}
// 通过getUpperBounds得到上界,即派生自extends的限定,如果没有,默认是Object
Type[] upperBounds = wt.getUpperBounds();
for (Type bound : upperBounds) {
Class<?> boundClass = (Class) bound;
// 如果不写,则默认输出Object,如果写了,则输出对应的
System.out.println("upperBound为:" + boundClass.getName());
}
}
}
}
}
}
}
upperBound为:java.lang.Number
7)GenericArrayType
当type对应的类型是类似于String[]、Integer[]等的数组时,那type的类型就是GenericArrayType;这里要特别说明的如果type对应的是类似于ArrayList、List这样的类型,那type的类型应该是ParameterizedType,而不是GenericArrayType,因为ArrayList是一个泛型表达式。所以当且仅当type对应的类型是类似于String[]、Integer[]这样的数组时,type的类型才是GenericArrayType!
- getGenericComponentType()
这是GenericArrayType仅有一个函数,由于getGenericComponentType所代表的表达是String[]这种的数组,所以getGenericComponentType获取的就是这里的数组类型所对应的Type,比如这里的String[]通过getGenericComponentType获取到的Type对应的就是String.
interface GenericArrayInterface<T> {
}
class GenericArrayImpl<U> implements GenericArrayInterface<U[]> {
}
Class<?> clazz = GenericArrayImpl.class;
Type[] interfaces = clazz.getGenericInterfaces();
for (Type type : interfaces) {
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type[] actualArgs = pt.getActualTypeArguments();
for (Type arg : actualArgs) {
if (arg instanceof GenericArrayType) {
GenericArrayType arrayType = (GenericArrayType) arg;
Type comType = arrayType.getGenericComponentType();
System.out.println("数组类型为:" + comType.getTypeName());
}
}
}
}
数组类型为:U
8)通用的类型转换函数
private static void parseClass(Class<?> c) {
parseTypeParameters(c.getGenericInterfaces());
System.out.println();
}
private static void parseTypeParameter(Type type) {
if (type instanceof Class) {
Class<?> c = (Class<?>) type;
System.out.println(c.getSimpleName());
} else if (type instanceof TypeVariable) {
TypeVariable<?> tv = (TypeVariable<?>) type;
System.out.println(tv.getName());
parseTypeParameters(tv.getBounds());
} else if (type instanceof WildcardType) {
WildcardType wt = (WildcardType) type;
System.out.println("?");
parseTypeParameters(wt.getUpperBounds());
parseTypeParameters(wt.getLowerBounds());
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type t = pt.getOwnerType();
if (t != null) {
parseTypeParameter(t);
}
parseTypeParameter(pt.getRawType());
parseTypeParameters(pt.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
GenericArrayType arrayType = (GenericArrayType) type;
Type t = arrayType.getGenericComponentType();
parseTypeParameter(t);
}
}
private static void parseTypeParameters(Type[] types) {
for (Type type : types) {
parseTypeParameter(type);
}
}
parseClass(PointImpl.class);
parseClass(TypeVariableointGenericityImpl.class);
parseClass(PointWildcardImpl.class);
parseClass(GenericArrayImpl.class);
PointInterface
String
Double
TypeVariablePointInterface
T
Number
Serializable
Integer
PointSingleInterface
Comparable
?
Number
GenericArrayInterface
U
Object