泛型的简单使用

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






posted on 2018-02-09 12:54  刘达人186  阅读(150)  评论(0编辑  收藏  举报