• java-泛型


    编写泛型

    泛型(Generic)一般用在集合类中 编写泛型时,需要定义泛型类型

    public class Pair<T> { … }
    

    静态方法不能引用泛型类型,必须定义其他类型来实现“泛型”

    public static <K> Pair<K> create(K first, K last) { … }
    

    泛型可以同时定义多种类型<T, K>。

    public class Pair<T,K> { … }
    

    擦拭法

    擦拭法

    • Java的泛型(Generic)是采用擦拭法(Type Erasure)实现的。

    • 编译把视为Object

    • 编译器根据实现安全的强制转型

        我们写的是
        public static void main(String[] args) {
        	Pair<String> pair = new Pair<>("xiao","ming");
        	String first = pair.getFirst();
        }
      
        实际上编译器处理的是
        public static void main(String[] args) {
        	Pair pair = new Pair("xiao","ming");
        	String first = (String)pair.getFirst();
        }
      

    擦拭法的局限:

    • 不能是基本类型,例如int

    • Object字段无法持有基本类型

    • 无法取得带泛型的Class(返回的永远的同一个Class) 如:Pair<String>.class

    • 无法判断带泛型类型的类型,例如:x instanceof Pair<String>

    • 不能实例化 T 类型 如:new T();

    • 可以继承自泛型类:

        public class IntPair extends Pair<Integer> {
        }
      
    • 泛型方法要防止重复定义,例如: public boolean equals(T obj)

    • 子类可以获取父类的泛型类型。

    继承关系:

    Type
    |
    +- Class
    |
    +- ParameterizedType
    |
    +- GenericArrayType
    |
    +- WildcardType


    extends通配符

    使用类似<? extends Number>通配符作为方法参数时

    void someMethod(List<? extends Number> list) {
     Number n = list.get(0);
     list.add(n); // ERROR
    }
    允许传入List<Number>,List<Integer>,List<Double>...
    允许调用方法获取Number类型
    不允许调用方法传入Number类型(null除外)
    

    <T extends Number>定义泛型类

    定义泛型时可以通过extends限定T必须是Number或Number的子类
    

    super通配符

    使用类似<? super Integer>通配符作为方法参数时表示:

    • 允许传入List<Integer>List<Number>List<Object>

    • 允许调用方法传入Integer类型 set方法

    • 不允许调用方法获取Integer类型(Object除外)get方法

        void someMethod(List<? super Integer> list) {
        	list.add(123);
        	Integer n = list.get(0); // ERROR
        }
      

    使用类似定义泛型类型时表示:

    • 泛型限定为Integer或Integer的超类

    extends和super通配符的区别

    • 允许调用方法获取T的引用
    • 允许调用方法传入T的引用

    无限定通配符<?>

    • 只能获取Object引用

    • 只能传入null

    • 可以用消除<?>


    泛型和反射

    部分反射API是泛型:

    • Class

        Class clazz = String.class;
        String str = (String) clazz.newInstance();
      
        Class<String> clazz = String.class;
        String str = clazz.newInstance();
      
        Class<? super String> sup = clazz.getSuperclass();
      
    • Constructor

        Class<Integer> clazz = Integer.class();
        Constructor<Integer> cons = clazz.getConstructor(int.class);
        Integer i = cons.newInstance(123);
      
    • 可以声明带泛型的数组,但不能直接创建带泛型的数组,必须强制转型

        Pair<String> [] ps = null;					//正确
        Pair<String> [] ps = new Pair<String>[2];  	//错误
        
        @suppressWarnings("unchecked")
        Pair<String>[] ps = (Pair<String>[]) new Pair[2];  //正确
      
      • 不安全的使用带泛型的数组:

          public static void main(String[] args) {
          	Pair[] arr = new Pair[2];
          	Pair<String>[] ps = (Pair<String>[])arr;
          	
          	ps[0] = new Pair<String>("a","b");
          	arr[1] = new Pair<Integer>(1,2);
          	
          	
          	try {
          		//ClassCastException
          		Pair<String> p = ps[1];
          		
          	} catch (Exception e) {
          		System.err.println(e.getMessage()); //java.lang.Integer cannot be cast to java.lang.String
          	}
          }
        
      • 安全的使用带泛型的数组:

          @suppressWarnings("")
          Pair<String>[] ps = (Pair<String>[]) new Pair[2]; 
        
      • 带泛型的数组实际上是编译器进行类型的擦除

          Pair[] arr = new Pair[2];
          Pair<String>[] ps = (Pair<String>[]) arr;
          
          System.out.println(ps.getClass()==Pair[].class);//true
        
          String s1 = (String) arr[0].getFirst();
          String s2 = ps[0].getFirst();
        
    • 可以通过Array.newInstance(Class, int)创建T[]数组,需要强制转型

      • 不能直接创建T[]数组,擦拭后代码变为new Object[]

          //compile error:
          public class Abc<T>{
          	T[] createArray(){
          		return new T[5];
          	}
          }
        
      • 借助Class

          public class Abc<T>{
          	T[] createArray(Class<T> cls){
          		return (T[])Array.newInstance(cls,5);
          	}
          }
          
          //使用
          String[] s = new Abc<String>().createArray(String.class);
        
      • 利用可变参数创建T[]数组,@SafeVarargs消除编译警告

          public class ArrayHelper{
          	@SafeVarargs				
          	static <T> T[] asArray(T... objs){
          		return objs;
          	}
        
          	public static void main(String[] args) {
          		String[] ss = asArray("a","B","c");
          	}
          }
  • 相关阅读:
    我所理解的readonly和const
    代码中的良好习惯从点滴做起
    常用正则表达式收集
    优化网站加载速度的14个技巧
    关于easyUI的模态对话框
    关于jq ajax封装以及ajax上传Webapi
    Linux完全卸载Oracle的操作步骤
    Linux下安装oracle的一般步骤
    CentOS Linux上安装Oracle11g笔记
    Oracle中建库时报Exception in thread main
  • 原文地址:https://www.cnblogs.com/rogersma/p/11495132.html
Copyright © 2020-2023  润新知