泛型编程笔记

泛型编程
一个储存键值的泛型类
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的对象,省去了一次转换。





































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值