泛型限行上限和下限

来源:互联网 发布:windows命令行设置ip 编辑:程序博客网 时间:2024/05/01 01:07

泛型

泛型的作用是给我们用来判断类型的,

java代码
无泛型。
定义了两个javabean类。里面有String name

    public class Demo{        List list = new LinkedList();        public static void main(String[] args){            list.add(new Student("张三"));            list.add(new Student("李四"));            list.add(new Student("学生"));            list.add(new Teacher("老师"));        }        public Student get(List list ,String name ){            for(int index =0; index<list.size(); index++){                Student s = (Student )list.get(index);            }        }

运行时,这样就会报ClasscastException,如果我们不小心加了自己不想加的类型。我们将如何避免呢?如何把他变成编译时错误呢

java代码
有泛型。
定义了两个javabean类。里面有String name

public class Demo{        List<Student> list = new LinkedList<Student>();        public static void main(String[] args){            list.add(new Student("张三"));            list.add(new Student("李四"));            list.add(new Student("学生"));            list.add(new Teacher("老师"));//这个时候就已经报编译时错误        }        public Student get(List<Student> list ,String name ){            for(int index =0; index<list.size(); index++){                Student s = (Student )list.get(index);##泛型

泛型的作用是给我们用来判断类型的,
java代码
无泛型。
定义了两个javabean类。里面有String name

    public class Demo{        List list = new LinkedList();        public static void main(String[] args){            list.add(new Student("张三"));            list.add(new Student("李四"));            list.add(new Student("学生"));            list.add(new Teacher("老师"));        }        public Student get(List list ,String name ){            for(int index =0; index<list.size(); index++){                Student s = (Student )list.get(index);            }        }

运行时,这样就会报ClasscastException,如果我们不小心加了自己不想加的类型。我们将如何避免呢?如何把他变成编译时错误呢

java代码
有泛型。
定义了两个javabean类。里面有String name

public class Demo{        List<Student> list = new LinkedList<Student>();        public static void main(String[] args){            list.add(new Student("张三"));            list.add(new Student("李四"));            list.add(new Student("学生"));            list.add(new Teacher("老师"));//这个时候就已经报编译时错误        }        public Student get(List<Student> list ,String name ){            for(int index =0; index<list.size(); index++){                Student s = (Student )list.get(index);            }        }

这样我们就解决了问题, 注意 :我要遵守 左右泛型相同,虽然很容易忘记。

类型擦除

接下来我们看什么叫类型擦除?

Java的泛型是伪泛型。为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。

Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

如在代码中定义的List和List等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。

BZ在这里就不一一的说了,我就给个链接。那里会十分详细的解析,
BZ看了受益匪浅 ,有种大彻大悟的感觉,总结十分好。类型擦除的详解

限行上限和下限

代码体现:

上限

TreeSet(Collection<? extends T>){}

下限

TreeSet(Collection<? super T>){}

上限的优点

如果一个集合 泛型是这样的,Collection < Student >,那么将意味着我们只能往集合里添加Student 类型地点数据了;那么有了学生的时候 我们还想添加老师的数据怎么办?这时我们只能再建一个Collection < Teacher > ,那么又有一种情况 ,我们需要把Student 和Teacher 放在同一个集合里(Student,Teacher都是Person的子类),只能提升类型,后放入Collection < Person> 中,取出来需要使用student 或者 teacher特有方法时 ,必须 强转回去。这样我们将会很麻烦,甚至我们将不能强转回原来的数据类型。这时候如果没点其他方法 ,这样泛型对数据类型的限定将太过唯一了。
这时候我们将可以使用泛型上限了。

TreeSet < ? extends T>

当然你想这么写 必须在Api上构造放上有相关的定义才能这样写,或者在自己写API上也可以这么定义。这里我们将那TreeSet来举个例子。

泛型上限的试例

public class Demo{    public static void main(String[] args){        Collection < Student > set = new TreeSet < Student >();         set.add("zzr",1);        第一种方法://Set < Person > set1 = new TreeSet < Person> ();        //set1.addAll(set);//1.      编译通过。        Set < Person > set1 = new TreeSet < Person> (set);//2.        for(Iterator it = set1.iterator();it.hasNext();){            Person p  = it.next();//3.            System.out.println(p.toString());//可省略        }    }}

位置1. 我想拿出来说,或许我这样写第一次看的人还是看不懂,
boolean addAll(Collection< ? extends E > c)
将指定 collection 中的所有元素添加到此 set 中。
这里就是出现了 我们上面写的Collection< ? extends E >
? 是通配符
我们是调用set1 的addAll() 这是E是Person 也是就是说只要是继承了Person 的 泛型都可以传入 能接受,能接受就可以了!

2.TreeSet(Collection< ? extends E > c)
构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。

其实和上面的道理一样 , 只能传进去就可以。

3.不过大家肯定会迷惑穿进去到底是保持原来的类型还是给升到Person类型,如果你仔细的看我类型擦除的那里一定会知道,泛型的作用只是在引用上起到检查作用,当变成字节码文件,就会擦去。在存储的时候会变成Object 类型才存储,但是当我们提取 是Object 呢 还是 Person 还是Student

看下ArrayList和get方法:

public E get(int index) {      RangeCheck(index);      return (E) elementData[index];     } 

所以这里应该是返回Person。

下限

我们这里 还是拿TreeSet 做例子。
需求 一个Comparator 同对两个不同泛型变量的集合。如果不用到到泛型下限的话,我们只能创建两个比较器(comparator).

例如数据类型Student

public class MyComparator1 implements Comparator< Student> {    public int compara(Student o1,Student o2){        int temp =o1.getName().comparaTo(o2.getName());        return temp==?o1.getAge() - o2.getAge() : temp;    }}

或许我在这里放个源码大家会更加清晰

interface Comparator< T >{    int compare(T o1, T o2) ;    boolean equals(Object obj) ;}

如果我们使用下限的话,就可以只创建一个比较器了。
BZ就在这里说一下自己的理解。当我们实现了Comparator接口,int compare(T o1, T o2) 的泛型也确定了,有人会说可以这么写:

不去确定泛型变量

public class MyComparator1< T > implements Comparator< T> {    public int compara(To1,To2){        int temp =o1.getName().comparaTo(o2.getName());        return temp==?o1.getAge() - o2.getAge() : temp;    }}

bz也觉得这样是可行的。但是我们这里还是学习这个做法。大家也知道当父类引用可以调用子类的东西所继承的东西,所以如果这两个都同时继承一个类。那我们怎么限定到只有这个子类对象 和 父类对象 以及以上的对象才能传进来呢?是不是在数学上来说有下限无上限呢?

TreeSet(Comparator< ? super E> comparator)
构造一个新的空 TreeSet,它根据指定比较器进行排序。

父类数据类型Person

public class MyComparator1 implements Comparator< Person > {    public int compara(Person o1,Person o2){        int temp =o1.getName().comparaTo(o2.getName());        return temp==?o1.getAge() - o2.getAge() : temp;    }}

这时候大家是不是会对上限和下限的理解更加的深刻了一些。

0 0
原创粉丝点击