泛型编程笔记

xiaoxiao2021-02-28  65

泛型编程 一个储存键值的泛型类 public class Entry<K,V>{     private K key;     private V value;     public Entry(K key,V value){         this.key = key;         this.value = value;     }     public K getKey() {         return key;     }     public V getValue() {         return value;     } } 值得注意的是: Entry<String,int> a;//不能用基本类型实例化,int是基本类型,需要用Integer Entry<String,Integer> entry = new Entry<>("www",123); 泛型方法 public class Arrays {     public static <T> void swap(T[] array,int i,int j){//声明一个泛型方法时,类型参数要放在修饰符(public、static)之后。返回类型之前         T temp = array[i];         array[j] = array[i];         array[i] = temp;     } } Arrays.swap方法可以交换任何数组元素(只要数组中的元素类型不是基本类型)。 类型限定 public static <T extends AutoCloseable> void closeAll(ArrayList<T> elems)//如果有多个限定用&连接,比如T extend AutoCloseable & Runnable throws Exception{ for(T elem:elems) elem.close(); } extends AutoCloseable确保了elem.close是有效的,因为元素类型是AutoCloseable的子类型。 try { Arrays.closeAll( new ArrayList<String>());//不可行,因为String不是AutoCloseable子类 }catch (Exception e){ e.printStackTrace(); } 类型变异和通配符 数组可以进行类型变异,比如Manager类是Employee的子类,可以将Manager[]数组传递给Employee[]; 数组列表不可以进行类型变异,如果将ArrayList<Manager>赋给ArrayList<Employee>,就会存在下述情况。 ArrayList<Manager> bosses = new ArrayList<>(); ArrayList<Employee> empls = bosses;//非法,但假设其可行 empls.add(new Employee(...));//则一个普通员工会存在于bosses中 如果一个方法从不对数组进行写操作,就不会破坏数组列表,可以用通配符表达这种情形 public static void printNames(ArrayList<? extends Employee> staff){//无论是什么类型,?都表示它是Employee的子类型,所以staff.get(i).getName()可以执行。 for(int i=0;i<staff.size();i++){ System.out.println(staff.get(i).getName()); } } 值得注意的是,不可以使用add方法,因为?可以表示任何子类。 父类型通配符 ?super Employee代表Employee的一个父类型 public static void printAll(Employee[] staff, Predicate<? super Employee> filter){// for(Employee e:staff){ if(filter.test(e)){ System.out.println(e.getName()); } } } Employee.printAll(new Employee[1],employee -> employee.toString().length()%2==0); //Predicate接口是固定不变的,Predicate<Employee>和Predicate<Object>之间没有任何关系,所以采用了Employee的父类型<? super Employee> PECS: produce(生产者) extends,consumer(消费者)super。从ArrayList中读取值,就是生产者,用extends.如果把Predicate用于测试,即为消费者,用super 带类型变量的通配符 Collections.sort()的定义: public static <T extends Comparable<? super T>> void sort(List<T> list)//在这里用<? super T>的原因是防止Comparable的限制过于严格,在出现子类型继承父类型时,可能产生意外的影响。 只要T是Comparable的子类型,sort方法就可以对任意List<T>进行排序,而Comparable接口也是泛型的 public interface Comparable<T>{ int compareTo(T other); } 无限定通配符 public static boolean hasNull(ArrayList<?> objects){//元素类型无所谓,也可以采用泛型方法来实现 for (Object e:objects){ if(e == null){ return true; } } return false; } java虚拟机中的泛型 java语言设计者决定在实现上将类型从虚拟机中“擦除”,促使用户使用泛型。 类型擦除,编译的时候泛型类型会被编译成原始类型,比如最上方的Entry类的泛型,会被编译城Object 转换插入,即编译成Object,但是返回值会被强制转换,例如String key = (String)entry.getKey();Object类型被强制转换为String类型 泛型约束 1.无基本类型参数 即不能产生一个ArrayList<int> 2.所有类型在运行时都是原始的,即不能在运行时查询一个ArrayList是否包含一个String对象。即if(a instanceof ArrayList<String>)//非法   同样转换成泛型类型也是无效的,但却是合法的 Object result = new ArrayList<String>(); ArrayList<String> list = (ArrayList<String>)result;// @SuppressWarnings("unchecked") ArrayList<String> list = (ArrayList<String>)result; 滥用@SuppressWarnings会造成堆污染——本应该属于一个特定泛型类型实例对象,实际却属于一个不同的泛型,例如可以将一个ArrayList<Employee>赋值给ArrayList<String>引用。结果当检索到一个错误元素时,会抛出ClassCastException 3.不能实例化类型变量 public static <T> T[] repeat(int n,T obj){ T[] result = new T[n];//非法,不能用new T[...]构造一个数组 for(int i=0;i<n;i++){ result[i] = obj; } return result; } 通过反射机制构建,参考了反射的那章的复制数组代码     public static <T> T[] repeat(int n,T obj){         Class<?> c = obj.getClass();         Object newArray = Array.newInstance(c,n);         for(int i=0;i<n;i++){             Array.set(newArray,i,obj);         }         return (T[])newArray;     } 值得注意的是,可以使用类型变量实例化ArrayList,即ArrayList<T> result = new ArrayList<>();//合法 4.不能构造参数化类型的数组 Entry<String ,Integer>[] entries = new Entry<String,Integer>[100];//非法,因为类型擦除后,数组构造函数将会创建一个原始的Entry数组,可以添加任意对象 Entry<String ,Integer>[] entries2 = (Entry<String, Integer>[]) new Entry<?,?>[100];//合法,强制转换为对应类型 更简单是的构造数组列表。 5.静态上下文中的类类型变量不是有效的 即不能在静态变量或者静态方法中使用类型变量 6,类型擦除后的方法可能会冲突 类型擦除后的T被编译为Object有的方法会和Object自带的方法产生冲突 7.异常与泛型 不能够抛出或者捕获一个泛型类对象,甚不能构建一个Throwable的泛型子类 public class Problem<T> extends Exception//非法--泛型类不能是Throwable的子类 catch子句中可不能使用泛型变量 反射与泛型 Class<T>类 public Class<T>{ public T newInstance() throws...{...} } 直接返回一个类型为T的对象,省去了一次转换。
转载请注明原文地址: https://www.6miu.com/read-2623193.html

最新回复(0)