黑马程序员——012——JavaAPI④(集合框架(泛型)、泛型类、泛型方法、泛型限定)

来源:互联网 发布:淘宝会员名怎么更改 编辑:程序博客网 时间:2024/05/20 18:40
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

泛型
引入:首先我们来看一个实例代码:
———————————————————————————

import java.util.*;class Demo12_1{        public static void main(String[] args)        {                //定义一个ArrayList容器                ArrayList al = new ArrayList();                al.add("halo1");                al.add("halo2");                al.add("halo3");                al.add(4);//相当于al.add(new Integer(4))                Iterator it = al.iterator();                while(it.hasNext())                {                        String s = (String)it.next();//抛异常                        System.out.println(s);                }        }}

———————————————————————————
执行结果:在“String s = (String)it.next();”处抛异常;
这里写图片描述
表现为:编译没问题,运行有问题;
—这就可能使得程序员在开发的时候不能及时的发现问题,因此JDK在1.5版本以后出现了新特性,用于解决安全问题,是一个类型安全机制。
—我们再来回顾一下升级的三个目的:
——①高校;
——②简化书写;
——③安全;
——显然这个泛型是为了安全而来的;
——如果我们用了泛型对以上程序进行改写,我们就能够把问题转移到编译期:
———————————————————————————

import java.util.*;class Demo12_2{        public static void main(String[] args)        {                //定义一个ArrayList容器                ArrayList<String> al = new ArrayList<String>();                al.add("halo1");                al.add("halo2");                al.add("halo3");                //al.add(4);//抛异常                Iterator<String> it = al.iterator();                while(it.hasNext())                {                        String s = it.next();                        System.out.println(s);                }        }}

———————————————————————————
这时候程序编译运行都没有问题了,注意一下几个地方的改变:
(图a)
这里写图片描述
———————————————————————————
而且我们会发现编译的反馈信息也发生了改变:加了泛型之后,不安全的信息也没有了。
这里写图片描述
泛型好处:
—①将运行时期出现问题ClassCastException,转移到了编译时期,方便于程序员解决问题。让运行事情问题减少,安全;
—②避免了强制转换麻烦;((图a)的箭头处不需要强制转换类型了)
——而1.5以前,1.4…等,程序员需要主观判定里面存什么类型的元素;
———————————————————————————
泛型使用
泛型格式:
—通过<>来定义要操作的引用数据类型;
使用情形:
—通常在集合框架中很常见;只要见到<>就要定义泛型;
——其实<>就是用来接收类型的;
——当使用集合的时候,将集合中要存储的数据类型作为参数传递到<>中即可;
—接口Comparable的compareTo方法可以使用泛型来避免强转;
—接口Comparator的compare方法也可以使用泛型来避免强转;
—Iterator迭代器也可以定义泛型避免强转;
注意:
Object中的equals方法就没有泛型来避免强转了,一定多态,必要的时候一定得强转了;
我们加入泛型在将前面小节中的学生工人的实例重写一下:
—需求:
——工人对象不具备比较性,将若干工人对象存入HashSet集合;
——学生对象具备比较性,将若干学生对象存入TreeSet集合,并且按照年龄小大顺序排序;
———————————————————————————

import java.util.*;class Demo12_3{        public static void main(String[] args)        {                //定义一个装工人的集合HashSet,并用泛型声明该集合只能够装工人类对象                HashSet<Worker> hs = new HashSet<Worker>();                hs.add(new Worker("工人1",23));                hs.add(new Worker("工人2",25));                hs.add(new Worker("工人1",27));//同姓名不同年龄                hs.add(new Worker("工人4",23));//同年龄不同姓名                System.out.println(hs);                //打印结果:[工人4-23, 工人2-25, 工人1-23, 工人1-27]                //定义一个装学生的集合TreeSet,并用泛型声明该集合只能够装学生类对象                TreeSet<Student> ts = new TreeSet<Student>();                ts.add(new Student("学生1",23));                ts.add(new Student("学生2",25));                ts.add(new Student("学生1",27));//同姓名不同年龄                ts.add(new Student("学生4",23));//同年龄不同姓名                System.out.println(ts.add(new Student("学生2",25)));//同年龄同姓名,同一个人添加失败                System.out.println(ts);                //打印结果:[学生1-23, 学生4-23, 学生2-25, 学生1-27]        }}/*工人类*/class Worker{        private String name;        private int age;        public Worker(String name,int age)        {                this.name = name;                this.age = age;        }        public String getName()        {                return this.name;        }        public int getAge()        {                return this.age;        }        public int hashCode()        {                return this.name.hashCode()+this.age*37;        }        public boolean equals(Object obj)        {                if(!(obj instanceof Worker))                        throw new RuntimeException("不是Person类型的元素");                Worker w = (Worker)obj;                return this.name.equals(w.getName()) && this.age == w.getAge();        }        public String toString()        {                return this.name+"-"+this.age;        }}/*学生类*/class Student implements Comparable<Student>//泛型的定义{        private String name;        private int age;        public Student(String name,int age)        {                this.name = name;                this.age = age;        }        public String getName()        {                return this.name;        }        public int getAge()        {                return this.age;        }        public int hashCode()        {                return this.name.hashCode()+this.age*37;        }        /*覆盖equals方法*/        public boolean equals(Object obj)        {                if(!(obj instanceof Student))                        throw new RuntimeException("不是Person类型的元素");                //equals方法中必须要强制转型了                Student s = (Student)obj;                return this.name.equals(s.getName()) && this.age == s.getAge();        }        /*重写接口的compareTo方法,        参数设置成和泛型一致的类型,不需要强转了*/        public int compareTo(Student s)        {                //按照年龄排序                //包装成Integer类,调用Integer已经实现的compareTo方法                int comResult = new Integer(this.age).compareTo(s.getAge());                if(comResult==0)//年龄一致再用姓名排序                        return this.name.compareTo(s.getName());                return comResult;        }        public String toString()        {                return this.name+"-"+this.age;        }}

———————————————————————————
执行结果:
这里写图片描述
总结:
—HashSet无序不重复;
—TreeSet可以排序不重复;
———————————————————————————
泛型类
诸如Comparable接口和Comparator接口等,这种类后面是跟着<类型>的类,就是泛型类(接口也是特殊的类)。
—何时定义泛型类:
——当类中要操作的引用数据类型不确定的时候,早期定义Object来完成拓展,有了泛型之后就可以定义泛型来完成扩展了;
——注意只能够是引用类型的,<>中间不能够放基本类型;
——如下面的例子:一个自定义的泛型类
———————————————————————————

class Demo12_4{        public static void main(String[] args)        {                Utils<String> u = new Utils<String>();                //QQ是什么,由传进去的类型决定,这里就是String                u.setObject(new String());//只能够传入String类型的                u.setObject(new Integer());//如果传入String以外类型的会报错                //将问题转移到了编译时期,不再需要使用instanceof判断类型了        }}/*自定义泛型类*/class Utils<QQ>//QQ为泛型类型,只是一个替代单词{        private QQ q;        public void setObject(QQ q)        {                this.q = q;        }        public QQ getObject()        {                return q;        }}

———————————————————————————
泛型方法
泛型除了定义在类上,还可以定义在方法上,以上的例子Utils的setObject的参数也是泛型,不过并不是我们要讲的,先观察看下面的代码:
———————————————————————————

class Demo12_5{        public static void main(String[] args)        {                GenericClass1 gc1 = new GenericClass1();                gc1.show("halo");//调用show(String s)方法                gc1.show(1);//调用show(Integer i)方法                GenericClass2<String> gc2 = new GenericClass2<String>();                gc2.show("halo");//调用show方法                GenericClass2<Integer> gc3 = new GenericClass2<Integer>();                //然而这时候泛型已经固定为Integer类型了,不能改变了                gc3.show(1);//调用show方法        }}class GenericClass1{        /*        类上不用泛型,定义show方法,        要求只有一个参数,        并且既能够接收String类型,        也能够接收Integer类型参数        并且打印        */        //不用泛型,参数需要多少个类型就要写多少个show方法        public void show(String s)        {                System.out.println("show:"+s);        }        public void show(Integer i)        {                System.out.println("show:"+i);        }}/*定义泛型类*/class GenericClass2<T>{        /*        类上使用泛型,定义show方法,        要求只有一个参数,        并且既能够接收String类型,        也能够接收Integer类型参数        并且打印        */        //使用用泛型,上面的方法都可以删除了        public void show(T t)        {                System.out.println("show:"+t);        }}

———————————————————————————
正如代码中注释所说的,在GenericClass1的时候要想show方法能够接受多种参数,就需要重载出很多的方法;而在GenericClass2的时候想show方法能够接受多种参数,只需在new对象的时候传入一个类型即可。
用简单的话描述一下就是:
—以前在没有泛型的时候,参数不一样需要定义多个重载方法来适配需求:
—而现在不需要了,有了泛型,一个全搞定:
—然而我们也看到了,泛型类一旦建立了对象,那么其泛型的类型就固定不可更改了,那么我们就想如果不在类上定义泛型,而在方法上定义泛型的话,那么是不是就可以建立的对象的时候泛型还是泛型,而不会具体类型呢。我们来看下面代码:
———————————————————————————

class Demo12_6{        public static void main(String[] args)        {                GenericClass gc = new GenericClass();                gc.show("halo");//调用show(String s)方法                gc.show(1);//调用show(Integer i)方法        }}/*泛型在方法上的类*/class GenericClass{        /*        show方法上定义泛型        */        public <T> void show(T t)        {                System.out.println("show:"+t);        }}/*泛型在类上和方法上的类*/class GenericClass1<T>{        /*        show方法上定义泛型        */        public void print(T t)//访问类上定义的泛型        {                System.out.println("print:"+t);        }        /*        show方法上定义泛型        */        public <Q> void show(Q q)        {                System.out.println("show:"+q);        }}

———————————————————————————
总结:
—①泛型定义在类上不如泛型定义在方法上灵活,因为方法的泛型是根据参数类型而转变的,而类上的泛型则是根据new对象的时候固定下来只有一种了;
—②当然两者不冲突,可以同时定义,如上面的GenericClass1类;
———————————————————————————
既然类上的泛型涉及到需要new对象才能够确定,那么如果有静态方法参数访问到了该泛型,这时候泛型是什么类型还没有固定下来,会如何呢?
—所以我们有了总结③
—③如果是静态方法的参数使用的泛型,那么泛型必须定义在该方法上(因为在内存中静态方法比对象先有);
——书写格式:
———(正确)public static void method(W w){…}
———(错误)public static void method(W w){…}
———记住泛型写在返回类型的前面
———————————————————————————
泛型接口
泛型定义在接口上,如:
————————————————————

interafce Inter<T>{    void show(T t);}class InterImpl implements Inter<String>//泛型固定位String类型{    public void show(String t)    {        System.out.println("show:"+t);    }}class Demo12_7{    public static void main(String[] args)    {        InterImpl i = new InterImpl();        i.show("haha');    }}

————————————————————
若实现接口的类继续使用泛型,不知道需要什么类型(类型不明确):
————————————————————

class InterImpl<T> implements Inter<T>//泛型确切类型还没固定{    public void show(T t)    {        System.out.println("show:"+t);    }}class Demo12_8{    public static void main(String[] args)    {        /*        InterImpl i = new InterImpl();        i.show("haha');        */        InterImpl<Integer> i = new InterImpl<Integer>();        i.show(5);    }}

———————————————————————————
泛型的高级应用(泛型限定)
使用通配符的方式将泛型能够确定的类型限定在一个范围内,通配符也可以理解为占位符。
有3种方式:
—第①种:

import java.util.*;class Demo12_9{        public static void main(String[] args)        {                TreeSet<Student> ts = new TreeSet<Student>(new Com());                ts.add(new Student("cbc"));                ts.add(new Student("obc"));                ts.add(new Student("abc"));                ts.add(new Student("dbc"));                show3(ts);        }        /*        //使用<?>方式        public static void show1(TreeSet<?> ts)        {                Iterator<?> it = ts.iterator();                while(it.hasNext())                {                        System.out.println(it.next().getName());                        //getName是Person的特有方法                        //因为使用了?占位符,因此getName不能够使用了                }        }        //使用<T>方式        public static <T> void show2(TreeSet<T> ts)        {                Iterator<T> it = ts.iterator();                while(it.hasNext())                {                        System.out.println(it.next().getName());                        //和上面原因差不多,getName不能够使用了                }        }        */        public static void show3(TreeSet<? extends Person> ts)        {                Iterator<? extends Person> it = ts.iterator();                while(it.hasNext())                {                        //因为做了泛型的上限限定Person的子类,                        //因此Person体系下的特有方法getName可以使用了                        System.out.println(it.next().getName());                }        }}/*定义人类*/class Person implements Comparable<Person>{        private String name;        public Person(String name)        {                this.name = name;        }        public String getName()        {                return this.name;        }        public int compareTo(Person p)        {                return this.name.compareTo(p.getName());        }}/*定义学生类,继承自人类*/class Student extends Person{        public Student(String name)        {                super(name);        }}/*定义人类比较器*/class Com implements Comparator<Person>{        public int compare(Person p1,Person p2)        {                return p1.getName().compareTo(p2.getName());        }}

———————————————————————————
以上就是关于

import java.util.*;class Demo12_10{        public static void main(String[] args)        {                //TreeSet<Person> ts = new TreeSet<Person>(new WorkerComp());                //由于比较器限定了Worker类型以及其父类,也就是Person,                //所以这个比较器就不能够使用Student的实例的了                //TreeSet<Person> ts = new TreeSet<Person>(new StudentComp());                //由于比较器限定了Student类型以及其父类,也就是Person,                //所以这个比较器就不能够使用Worker的实例的了                //使用new PersonComp()作为通用比较器                //而不用每个类都定义一种比较器,应用泛型                //因为TreeSet的构造函数                //TreeSet(Comparator<? super E> comparator)                TreeSet<Person> ts1 = new TreeSet<Person>(new PersonComp());                ts1.add(new Student("sabc01"));                ts1.add(new Student("sabc04"));                ts1.add(new Student("sabc03"));                ts1.add(new Student("sabc02"));                show(ts1);                TreeSet<Person> ts2 = new TreeSet<Person>(new PersonComp());                ts2.add(new Worker("wabc01"));                ts2.add(new Worker("wabc04"));                ts2.add(new Worker("wabc03"));                ts2.add(new Worker("wabc02"));                show(ts2);        }        public static void show(TreeSet<? extends Person> ts)        {                Iterator<? extends Person> it = ts.iterator();                while(it.hasNext())                {                        System.out.println(it.next().getName());                }        }}/*学生比较器*/class StuComp implements Comparator<Student>{        public int compare(Student s1,Student s2)        {                return s1.getName().compareTo(s2.getName());//顺序        }}/*工人比较器*/class WorkerComp implements Comparator<Worker>{        public int compare(Worker w1,Worker w2)        {                return w1.getName().compareTo(w2.getName());//顺序        }}/*用一个比较器代替上面两个比较器*/class PersonComp implements Comparator<Person>{        public int compare(Person p1,Person p2)        {                return p1.getName().compareTo(p2.getName());//顺序                //return p2.getName().compareTo(p1.getName());//倒序        }}class Person{        private String name;        public Person(String name)        {                this.name = name;        }        public String getName()        {                return this.name;        }}class Student extends Person{        public Student(String name)        {                super(name);        }}class Worker extends Person{        public Worker(String name)        {                super(name);        }}

———————————————————————————
以上实例就是

0 0
原创粉丝点击