java核心技术- 泛型技术

泛型基础:

泛型的常见问题

/*泛型是在不确定类型的情况下使用。用与在使用时再确定属性方法实例要操作的类型

 * 1.静态方法泛型必须定义在方法上。不能使用类的泛型。

 * 2.方法的泛型可以和类的泛型不同。

 3.当操作对象与泛型不一致时发生编译错误。泛型就是提供给编译器的安全检查机制,可以作为安全检查机制来使用。

4.当类,接口,方法操作的对象不确定类型时。使用泛型。泛型在继承和实现时可以连续传递。

class asd<E>{

       public static <Q>void sdf(Q q){          

       }

       public <E> void dfg(E e){             

       }

}

//此接口要操作的对象不确定。

interface inter<E>{

       public void show(E e);

}

//此类要操作的对象明确为String.

class jk implements inter<String>{

       public void show(String e) {          

       }

}

// 此类所操作的对象不确定类型。

class ko<E> implements inter<E>{

public void show(E e) {  

       }    

}

class student{     

}

class worker{       

}

class asd<E>{       

       void sdf(E e){             

       }

       <Q> void fgh(Q q)             

       }

       <E>void ghj(E e){             

       }

       static void jlk(E e){

             //错误   不能直接使用类的泛型。

       }

    static<E> void jlsk(E e){

             //正确   必须自定义泛型

       }            

}

 * 可以对类型进行限定:  

* ? extends E:接收E类型或者E的子类型对象。上限!   *   

* ? super E :接收E类型或者E的父类型。下限!

一般使用上限 通常对集合中的元素进行取出操作时,可以是用下限。

泛型擦除: 当编译后,泛型就不存在了。

泛型代码和虚拟机

  • 问题: 编译器如何擦除类型变量,变为确定的类型?,对虚拟机来说,所有对象都属于普通类。
  • 每定义一个泛型就会对应有一个原始类型,。擦除(erased) 类型变M, 并替换为限定类型(无 限定的变量用 Object)。 
  • 其原始类型以第一限定 Comparable 为准。若某接口仅作为标记,应放再右边,因为编译器可能对 Comparable 进行强转
  • 翻译泛型表达式

  • 编译器再擦除泛型是,将会自动插入强制类型转换,最后生成字节码文件。编译器把这个方法调用翻译为两条虚拟机指令: 
  • 当存取泛型域是也要插入强转
  • java泛型转换的事实

  • •虚拟机中没有泛型,只有普通的类和方法。 
  • •所有的类型参数都用它们的限定类型替换。 
  • •桥方法被合成来保持多态。 
  • •为保持类型安全性,必要时插人强制类型转换
  • 泛型约束和局限性

  • 不能用类型参数代替基本类型。因此, 没有 Pair<double>, 只 有 Pair<Double>
  • 运行时类型查询只适用于原始类型,instanceof 对Pair<String> 治测试是否是pair. getClass方法也治返回pair.class
  • 不能创建参数化类型的数组,即泛型数组不可用,可以使用List集合替代。
  • Varargs警告:java不支持泛型数组,但在接受多个泛型参数时,虚拟机会自动创建一个泛型数组。但会得到一个警告。
  • public static <T> void addAll(Collections coll, T... ts)    ts会被创建为泛型数组。
  • 该警告: @SafeVarargs 或者  @SuppressWamings("unchecked")标注。  
  • 在泛型类中不能对T实例化,因为类型擦除 T -》 Object ,将会创建Object实例,无意义。
  • T.class 不合法,若要创建T的实例,必须有实际T的class传入,该方法可以依靠这个class创建实例。
  •  禁止使用带有类型变量 的静态域和方法。即不能使用泛型类的泛型。
  • 至泛型类扩展 Throwable 是不合法的。public class Problem<T> extends Exception { /* ...*/ } // Error can't extend Throwable 
  • catch 子句中不能使用类型变量。catch (T e) // Error can't catch type variable 
  •  在异常规范中使用类型变量是允许的。public static <T extends Throwable〉void doWork(T t) throws T // OK
     
  • 消除对已检查异常的检查(欺骗编译器使其认为这是一个 RuntimeException) 
  •     public void asd() throws Throwable {
            Throwable t = new Throwable();
            System.out.println(t+"1");
            try{
                throw t;
            }catch (Throwable w){
                //使用泛型欺骗编译器,使其认为抛出了未检查异常,此时不需要 throws Throwable
                mytest.<RuntimeException>throwAs(w);
                System.out.println(w+"2");
                //此时需要 throws Throwable,否则编译不通过。
                adsd();
            }
        }
        //抛出已检查异常
        public void adsd() throws Throwable {
            throw new Throwable();
        }
        //使用泛型欺骗编译器,使其认为抛出了未检查异常
        @SuppressWarnings("unchecked")
        public static <T extends Throwable> void throwAs(Throwable e)throws T{
            T t = (T) e;
            System.out.println(t+"3");
            throw t;
        }

     

 

  • 这里说明,该泛型方法确实会欺骗编译器。但是由输出中间结果看到 为Throwable3 ,而不是Runtime3。即其实际抛出的仍为 Throwable ,但为什么编译器会认为这是一个未检查异常。???????????
  •  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值