java基础复习(13)--java泛型

泛型:
public static <T> T gMethod(List<T> list){.....}
这种语法和generic classes有相当程度的不同:泛型符号<T>必须加在class名称之后,却必须加在method名称(及回传型别)之前。


jdk1.5还允许将“不被method实际用到”的型别参数以符号‘?’表示,例如:

 

public static List<?> gMethod(List<?> list){
    return list;//本例简单地原封不动传回
}
 


此例gMethod()接受一个List(无论其元素型别是什么),传回一个list(无论其元素型别是什么)。由于不存在(或说不在乎)型别参数(因为metho内根本不去用它),也就不必如平常一般在回传型别之前写出<T>来告知编译器了。

参数化型别的序列化:
将LikedList<Integer>得list序列化到文件中,然后读出,不过以下转换jdk1.5编译器会发出警告:


LinkedList<Integer> list1 = (Linkedlist<Integer>)in.readObject(); 告诉我们“unchecked cast”(jdk1.4则直接报错)


其他形式也不可以,比如:

 

LinkedList list1 = (LinkedList<Integer>)in.readObject();
 

只能写成这样:

 

LinkedList list1 = (LinkedList)in.readObject();


以上事实告诉我们,当object被写入文件,即失去其泛型型别参数(如果有的话)。因此读回的只是非泛型的class信息

 

如果上面的代码改写如下:

 

ArrayList list2 = (ArrayList)in.readObject();//可以顺利编译,在编译器的眼里是没问题的,但在执行时会出现异常,报类转换异常。
 

 

将对象序列化后,在序列化文件中记录的类的名称是java.util.LinkedList,并一并记录了元素型别java.lang.Integer(及其base class java.lang.Number).这些记录对于反序列化过程中恢复容器原型和内容有其必要,但无法让编译器推论当初使用的是LinkedList容器或是LinkedList<Integer>容器。

 

 

 

如果collection被参数化,则Iterator也应该使用相同的参数。

 List list = new ArrayList();
        list.add("1");
        list.add("2");
        list.add("3");
        for(Iterator<String> itr = list.iterator();itr.hasNext();){
            String s = itr.next();
            System.out.println(s);
        }
 


以上代码编译和运行都没有问题。

List list = new ArrayList();
        list.add(1);//加入的是数值,但在后面的iterator中,却期望的是String类型。
        list.add("2");
        list.add("3");
        for(Iterator<String> itr = list.iterator();itr.hasNext();){
            String s = itr.next();
            System.out.println(s);
        }
 

以上代码编译没问题,但是在运行时出现类转换异常。所以在你将Iterator参数化得同时最好也参数化你的Collection,避免出现以上问题。

Map<String,List<List<int[]>>> map = getMap();

 

从这个map中取值会很抽象,int value = map.get(someKey).get(0).get(0)[0];
你无须对list做转换,而是让编译器来帮你拆解你的parameterized type。

 

 

Generic与类型转换
合法:

LinkedList<Integer> intList = new LinkedList<Integer>();
List<Integer> moreFloats = intList;
 


非法:
LinkedList<Number> numberList = intList;
分析(了解两件事情):


1,numberlList.add(1.2);//当从中取出并被当做一个int来使用时会导致一个ClassCastException
**在类型转换中要被考虑的所来自的基础类型,而不是参数类型**


2,“擦除”的概念。java中的generic是个编译期的程序,且所有的分类信息是在编译期被处理的。一旦class被编译过后,分类信息会被擦出掉。考虑下面两个声明:

 

List<Stirng> strings = new LinkedList<String>();
List<Integer> ints = new LinkedList<Integer>();

 

信息是用在编译期以执行类型检查,但分类信息在运行时就被舍弃了。因此,对jvm来说,这些声明就变成了:

List strings = new LinkedList();
List ints = new LinkedList();

 

现在没有类型参数了,在看看原来的代码 :

List<Integer> ints = new LinkedList<Integer>();
List<Number> nums = ints;


这在编译期看起来可能还OK,但在运行时它们是两个list,其中一个打算要转换成另一个,毫无任何的类型安全性。

抑制类型安全性:

 

List<Integer> ints = new LinkedList<Integer>();
//扩张它(为了向后兼容)
List oldList = ints;
//这一行应该是不合法的,但编译和运行后会过关。
oldList.add("hello");//我的想法:转换之后,它就不会有ints成员变量所具有的Integer的限制,List的元素默认是object了

 

ereasure移除了所有的参数化,只有在运行时,当要iterating该list来打印时,问题才会显露出来。

有时也会用到简单的旧式List,Map或其他没有被参数化的时候。这回引发unchecked错误,除非你才用了generic通配符。
在Eclipse下

List list = new ArrayList();//显示类型不确定的警告
解决方法:
List<?> list = new ArrayList<?>();//现在的语法已经表明---任何类型都是可以接受的,且unchecked警告也不见了。

 

合法的写法:

 

List<Integer> list = new LinkedList<Integer>();
List<?> test = list;

 

因为你已经将list声明为List<?>,现在get()返回的是一个object,那已经非常接近java中的“unknown”。虽然是同样的类型,但这与一个仅能够使用Object的List<Object>是非常不同的,更诡异的事情发生在add()与其他采用符合该collection类型参数的method上面。因为编译器无法检查以确保类型安全性,所以它会拒绝对List<?>的add(),addAll()与set()所做的任何调用。换言之,将generic类型赋予通配符会使其基本上并成只读的。

你可能感兴趣的:(java,eclipse,jvm)