zoukankan      html  css  js  c++  java
  • J2SE 8的泛型

    泛型的简单使用

    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






  • 相关阅读:
    使用YApi搭建API接口管理工具(docker安装)
    Redis 的持久化
    Typora编写markdown插入本地图片时自动上传图片到博客园
    关于python docker镜像环境下无法apt安装wkhtml2pdf的解决方案
    10分钟搞定让你困惑的 Jenkins 环境变量
    基于docker 搭建Prometheus+Grafana的过程详解
    docker方式搭建ELK日志平台
    ingress-nginx跨域解决
    k8s中pod优雅关闭进程
    java反编译命令
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710374.html
Copyright © 2011-2022 走看看