【JAVA】泛型 学习笔记

来源:互联网 发布:java 图片转avi 编辑:程序博客网 时间:2024/06/06 04:39

以下是我学习java集合框架的笔记,内容主要是个人理解和网络视频、文章的摘录。


首先为了方便下面代码的理解,这里先提一下一些下面会用到的三个对象:Person、StudentWorker

Person的属性只有String类型的name和int类型的age,其他就是一些基本的方法

Student和Worker都是完全继承Person类,都没有新的属性


下面开始正题

泛型,字面上理解是一个广泛的类型。

在jdk1.4版本之前,容器什么类型的对象都可以存储。但是在取出时,需要用到对象的持有内容时,需要做向下转型。但是对象的类型不一致,导致了向下转型发生了ClassCastException异常。为了避免这个问题,只能主观上控制,往集合中存储的对象类型保持一致。

jdk1.5以后解决了这个问题,在定义集合时,就直接明确集合中存储元素 的具体类型。这样,编译器在编译时,就可以对集合中存储的对象类型进行检查。一旦发现类型不匹配,就编译失败。这个技术就是泛型技术。

以下是一个例子

public static void main(String[] args) {List<String> list=new  ArrayList<String>();list.add("haha");list.add("abc");for(Iterator<String> it=list.iterator();it.hasNext();){String str=it.next();System.out.println(str);}}
这里的<String>就是泛型的表示

注:这里额外提醒int的类型的要写Integer

所以泛型具有以下优点

1:将运行时期的问题转移到了编译时期,可以更好的让程序员发现问题并解决问题

2:避免了向下转型的麻烦


总结:泛型就是应用在编译时期的一项安全机制


那么泛型是如何作用的呢?

泛型的擦除:编译器通过泛型对元素类型进行检查,只要检查通过,就会生成class文件,但在class文件中,就将泛型标识去掉了


泛型的表现:泛型技术在集合框架中应用的范围很大。什么时候需要写泛型呢?1:只要看到类,或者接口在描述的时候右边定义<>,就需要泛型。其实是,容器在不明确操作元素的类型的情况下,对外提供了一个参数<>。使用容器时,只要将具体的类型实参传递给该参数即可。简单来说,泛型就是,传递类型参数。


泛型类:jdk1.4时,类型向上抽取,当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成,但是这种方式有一种弊端,就是向下转型容易在运行时期发生ClassCastException。因此,jdk1.5以后,新的解决方案来了。就是类型不确定时,可以对外提供参数。有使用者通过传递参数的方式完成类型的确定。如下列例子,Util<w>就是一个泛型类

public class GenericDemo4 {public static void main(String[] args) {Util<Student> util=new Util<Student>();util.setObj(new Student());//如果类型不匹配,直接编译失败Student stu=util.getObj();//避免了向下转型System.out.println(stu);}}class Util<w>{private w obj;public final w getObj() {return obj;}public final void setObj(w obj) {this.obj = obj;}}

泛型方法:

public class GenericDemo5 {public static void main(String[] args) {// TODO Auto-generated method stubDemo<String> d=new Demo<String>();d.show("abc");//d.show(6);这个调用的不是泛型方法,6不是String类型,所以不对d.print("abc");d.print(6);d.staticShow(6);d.staticShow("abc");}}class Demo<W>{public void show(W w){System.out.println("show:"+w);}public static <A> void staticShow(A a){//这里注意,静态方法是无法访问类型上定义的泛型的。//如果静态方法需要定义泛型,泛型只能定义在方法上System.out.println("staticShow:"+a);}public <Q> void print(Q w){//泛型方法System.out.println("print:"+w);}}


泛型接口:
public class GenericDemo6 {public static void main(String[] args) {// TODO Auto-generated method stubSubDemo d=new SubDemo();d.show("abc");}}interface Inter<T>{//泛型接口public void show(T t);}//这是第一种用到接口的类,明确了类型是Stringclass InterImpl1 implements Inter<String>{@Overridepublic void show(String t) {// TODO Auto-generated method stub}}//这是第二种用到接口的类,没有明确类型,所以还是用的泛型。类型在他的子类SubDemo上定义class InterImpl2<w> implements Inter<w>{@Overridepublic void show(w t) {// TODO Auto-generated method stubSystem.out.println("show:"+t);}}class SubDemo extends InterImpl2<String>{}

通配符:

在不明确具体类型的情况下,可以使用通配符“?”来表示

public class GenericDemo7 {public static void main(String[] args) {List<Student> list=new ArrayList<Student>();list.add(new Student("abc1",21));list.add(new Student("abc2",22));list.add(new Student("abc3",23));printCollection(list);Set<String> set=new HashSet<String>();set.add("haha");set.add("xixi");set.add("hoho");printCollection(set);}private static void printCollection(Collection<?> coll) {//因为不确定是Person还是String类型,所以这里就使用了通配符for(Iterator<?> it=coll.iterator();it.hasNext();){Object obj=it.next();//这里注意使用了通配符,就要使用ObjectSystem.out.println(obj);}}}


限定

? extends E:接受E类型或者E的子类型,也就是限定了上限

? super E:接受E类型或者E类型的父类型,也就是限定了下限

(1)上限应用

public class GenericDemo9 {public static void main(String[] args) {// TODO Auto-generated method stubCollection<Student> coll=new ArrayList<Student>();coll.add(new Student("abc1",21));coll.add(new Student("abc2",22));coll.add(new Student("abc3",23));coll.add(new Student("abc4",24));TreeSet<Person> ts=new TreeSet<Person>(coll);ts.add(new Student("abc5",25));for(Iterator<Person> it=ts.iterator();it.hasNext();){Person person=it.next();System.out.println(person.getName());}}}class MyTreeSet<E>{MyTreeSet(){}MyTreeSet(Collection<? extends E> c){}}

(2)下限应用

public class GenericDemo10 {public static void main(String[] args) {Comparator<Person> comp=new Comparator<Person>(){@Overridepublic int compare(Person o1, Person o2) {// TODO Auto-generated method stubint temp=o1.getAge()-o2.getAge();return temp==0?o1.getName().compareTo(o2.getName()):temp;}};TreeSet<Student> ts=new TreeSet<Student>(comp);ts.add(new Student("abc1",21));ts.add(new Student("abc2",28));ts.add(new Student("abc3",23));ts.add(new Student("abc4",25));TreeSet<Worker> ts2=new TreeSet<Worker>(comp);ts2.add(new Worker("abc1",51));ts2.add(new Worker("abc2",58));ts2.add(new Worker("abc3",53));ts2.add(new Worker("abc4",55));for(Iterator<Student> it=ts.iterator();it.hasNext();){Student student=it.next();System.out.println(student);}for(Iterator<Worker> it=ts2.iterator();it.hasNext();){Worker worker=it.next();System.out.println(worker);}}}class YouTreeSet<E>{YouTreeSet(Comparator<? super E> comparator){}}
这里可以看出,无论是ts还是ts2,他们的父类都是Person,所以比较方法用Person为类型时,可以被他们使用




以上大多知识点摘自学习视频,如有侵权,请联系修改



原创粉丝点击