• 【JAVA之泛型】


    一、引例。

    1.引例。

    假设现在有一个ArrayList的容器,如果不使用泛型约束,则可以向容器中加入各种类型的对象,但是如果取出来的时候只是用一种类型的转换则肯定会抛出ClassCastException异常。

     1 package p04.GenerateTypeDemo.Demo01;
     2 
     3 import java.util.ArrayList;
     4 import java.util.ListIterator;
     5 
     6 public class Demo01 {
     7     public static void main(String args[])
     8     {
     9           ArrayList al=new ArrayList();
    10           al.add("abc1");
    11           al.add("abc2");
    12           al.add(1);
    13           al.add(2);
    14           ListIterator li=al.listIterator();
    15           while(li.hasNext())
    16           {
    17               String str=(String)li.next();
    18               System.out.println(str);
    19           }
    20     }
    21 
    22 }
    View Code

    虽然这个程序在Eclipse中编译时并没有报错,但是运行的时候则会产生ClassCastException异常,这样就产生了潜在的风险。虽然Eclipse没有报错,但是它会使用黄色小叹号提示程序员这样做有潜在的风险。该怎么保证在编译时期就确定是否有风险呢?泛型在JDK1.5之后就为此而产生了。

    泛型使用<>来表示,<>里面天上泛型的类型。这样容器就只能接收指定类型的对象了。

    更改代码:

     1 package p04.GenerateTypeDemo.Demo01;
     2 
     3 import java.util.ArrayList;
     4 import java.util.ListIterator;
     5 
     6 public class Demo01 {
     7     public static void main(String args[])
     8     {
     9           ArrayList<String>al=new ArrayList<String>();
    10           al.add("abc1");
    11           al.add("abc2");
    12           al.add(1);
    13           al.add(2);
    14           ListIterator<String> li=al.listIterator();
    15           while(li.hasNext())
    16           {
    17               String str=(String)li.next();
    18               System.out.println(str);
    19           }
    20     }
    21 
    22 }
    View Code

    这个代码相对上一个代码来说只是加入了泛型,其余均没有变化,但是在Eclipse中还没有运行就已经报错了。

    这就是使用泛型的最大好处。同时,也应当注意,使用泛型之后,迭代器也要使用泛型来定义将要迭代的元素类型,一旦这样做之后,取出元素的时候就不需要做强转动作了。

     1 package p04.GenerateTypeDemo.Demo01;
     2 
     3 import java.util.ArrayList;
     4 import java.util.ListIterator;
     5 
     6 public class Demo01 {
     7     public static void main(String args[])
     8     {
     9           ArrayList<String>al=new ArrayList<String>();
    10           al.add("abc1");
    11           al.add("abc2");
    12           al.add("abc3");
    13           al.add("abc4");
    14           ListIterator<String> li=al.listIterator();
    15           while(li.hasNext())
    16           {
    17               String str=li.next();
    18               System.out.println(str);
    19           }
    20     }
    21 
    22 }
    View Code

    2.总结:

    泛型是什么:泛型是JDK1.5之后出现的新特性。

    使用泛型的目的:为了提高安全机制。(JDK升级几乎只为了三个目的:提高效率、简化书写、提高安全性

    使用泛型的好处:

    1.将运行时期的问题ClasscastException转到了编译时期。

    2.避免了强制转换的麻烦。

    解惑:<>和E

    <>是什么?

    就像方法中使用()来界定参数范围,泛型使用<>界定要传入的参数类型。

    <>什么时候用?

    当操作的引用数据类型不确定的时候使用。

    E是什么?

    E代表一个参数,为Element的简写,不使用小写的原因就是E代表的参数类型只限于引用型数据类型,而不包括基本数据类型。

    3.泛型的擦除和补偿。

    擦除:虽然程序员在写代码的时候使用了泛型,但是在JAVA编译器生成Class文件的时候,会将泛型去掉,生成的Class文件中并没有泛型。这称为泛型的擦除。

    补偿:擦除的目的是为了兼容低版本jre,但是泛型技术中不使用强制转换却没有办法使得低版本支持,所以编译器略作调整,它将自动获取对象类型(使用getClass方法)并完成隐式的强转动作。这就是泛型的补偿。

    4.泛型类型所能使用的方法。

    一旦使用了泛型,则变量类型变得不确定,它将不能使用某个类的具体方法,但是能够使用Object类的所有方法。

    二、泛型类、泛型方法、泛型接口。

    1.泛型在TreeSet集合中的使用。

    TreeSet在集合框架中是比较复杂的一个容器,所以使用它作为演示容器。

     泛型在TreeSet中的常用使用方法:

    按照年龄排序:

     1 package p04.GenerateTypeDemo.Demo02.TreeSetDemo;
     2 
     3 import java.util.Iterator;
     4 import java.util.TreeSet;
     5 
     6 class Person implements Comparable<Person>
     7 {
     8     private String name;
     9     private int age;
    10     
    11     public Person() {
    12         super();
    13     }
    14     public Person(String name, int age) {
    15         super();
    16         this.name = name;
    17         this.age = age;
    18     }
    19     @Override
    20     public int hashCode() {
    21         final int prime = 31;
    22         int result = 1;
    23         result = prime * result + age;
    24         result = prime * result + ((name == null) ? 0 : name.hashCode());
    25         return result;
    26     }
    27     @Override
    28     public boolean equals(Object obj) {
    29         if (this == obj)
    30             return true;
    31         if (obj == null)
    32             return false;
    33         if (getClass() != obj.getClass())
    34             return false;
    35         Person other = (Person) obj;
    36         if (age != other.age)
    37             return false;
    38         if (name == null) {
    39             if (other.name != null)
    40                 return false;
    41         } else if (!name.equals(other.name))
    42             return false;
    43         return true;
    44     }
    45     @Override
    46     public String toString() {
    47         return "Person [name=" + name + ", age=" + age + "]
    ";
    48     }
    49     public String getName() {
    50         return name;
    51     }
    52     public void setName(String name) {
    53         this.name = name;
    54     }
    55     public int getAge() {
    56         return age;
    57     }
    58     public void setAge(int age) {
    59         this.age = age;
    60     }
    61     @Override
    62     public int compareTo(Person o) {
    63         //建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。
    64         int temp=this.age-o.getAge();
    65         return temp==0?this.name.compareTo(o.getName()):temp;
    66     }
    67 }
    68 public class TreeSetDemo {
    69 
    70     public static void main(String[] args) {
    71         TreeSet<Person> ts=new TreeSet<Person>();
    72         ts.add(new Person("zhangsan",25));
    73         ts.add(new Person("lisib",24));
    74         ts.add(new Person("lisia",24));
    75         ts.add(new Person("wangwu",29));
    76         ts.add(new Person("zhaoliu",22));
    77         
    78         for(Iterator<Person>it=ts.iterator();it.hasNext();)
    79         {
    80             Person p=it.next();
    81             System .out.println(p);
    82         }
    83         
    84     }
    85 
    86 }
    View Code

    覆盖自然排序,使用比较器按照姓名字典序排序:

     1 package p04.GenerateTypeDemo.Demo02.TreeSetDemo02;
     2 
     3 import java.util.Comparator;
     4 import java.util.Iterator;
     5 import java.util.TreeSet;
     6 
     7 class Person implements Comparable<Person>
     8 {
     9     private String name;
    10     private int age;
    11     
    12     public Person() {
    13         super();
    14     }
    15     public Person(String name, int age) {
    16         super();
    17         this.name = name;
    18         this.age = age;
    19     }
    20     @Override
    21     public int hashCode() {
    22         final int prime = 31;
    23         int result = 1;
    24         result = prime * result + age;
    25         result = prime * result + ((name == null) ? 0 : name.hashCode());
    26         return result;
    27     }
    28     @Override
    29     public boolean equals(Object obj) {
    30         if (this == obj)
    31             return true;
    32         if (obj == null)
    33             return false;
    34         if (getClass() != obj.getClass())
    35             return false;
    36         Person other = (Person) obj;
    37         if (age != other.age)
    38             return false;
    39         if (name == null) {
    40             if (other.name != null)
    41                 return false;
    42         } else if (!name.equals(other.name))
    43             return false;
    44         return true;
    45     }
    46     @Override
    47     public String toString() {
    48         return "Person [name=" + name + ", age=" + age + "]
    ";
    49     }
    50     public String getName() {
    51         return name;
    52     }
    53     public void setName(String name) {
    54         this.name = name;
    55     }
    56     public int getAge() {
    57         return age;
    58     }
    59     public void setAge(int age) {
    60         this.age = age;
    61     }
    62     @Override
    63     public int compareTo(Person o) {
    64         //建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。
    65         int temp=this.age-o.getAge();
    66         return temp==0?this.name.compareTo(o.getName()):temp;
    67     }
    68 }
    69 public class TreeSetDemo {
    70 
    71     public static void main(String[] args) {
    72         TreeSet<Person> ts=new TreeSet<Person>(new ComparatorByName());
    73         ts.add(new Person("zhangsan",25));
    74         ts.add(new Person("lisib",24));
    75         ts.add(new Person("lisia",24));
    76         ts.add(new Person("wangwu",29));
    77         ts.add(new Person("zhaoliu",22));
    78         
    79         out(ts);
    80     }
    81 
    82     private static void out(TreeSet<Person> ts) {
    83         for(Iterator<Person>it=ts.iterator();it.hasNext();)
    84         {
    85             Person p=it.next();
    86             System .out.println(p);
    87         }
    88     }
    89 
    90 }
    91 class ComparatorByName implements Comparator<Person>
    92 {
    93     @Override
    94     public int compare(Person o1, Person o2) {
    95         int temp=o1.getName().compareTo(o2.getName());
    96         return temp==0?o1.getAge()-o2.getAge():temp;
    97     }
    98 
    99 }
    View Code

    注意点:

    可以看到,不仅黄色小叹号不见了,而且在取出的时候少了强转动作。

    Person类在实现Comparable接口的时候,使用的泛型不是默认的Object,而是自定义的Person,这么做的好处就是类型明确,减少出错的几率,还避免了强转。

    equals方法不能修改参数类型,其参数必须是Object,想要使用必须强转。

    使用比较器的时候可以指定接受的泛型类型,这里是Person。

    自定义的比较器ComparatorByName只重写了compare方法,没有重写equals方法,原因是因为继承了Object类,所以已经默认被重写。

    2.泛型类。

    如果不使用泛型,取出对象的时候会产生异常:ClassCastException。

     1 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
     2 /*
     3  * 出现的问题。取出对象的时候出现了ClassCastException异常。
     4  */
     5 class Person
     6 {
     7     private String name;
     8     private String age;
     9     public Person() {
    10         super();
    11     }
    12     public Person(String name, String age) {
    13         super();
    14         this.name = name;
    15         this.age = age;
    16     }
    17     public String getName() {
    18         return name;
    19     }
    20     public void setName(String name) {
    21         this.name = name;
    22     }
    23     public String getAge() {
    24         return age;
    25     }
    26     public void setAge(String age) {
    27         this.age = age;
    28     }
    29     @Override
    30     public String toString() {
    31         return "Person [name=" + name + ", age=" + age + "]
    ";
    32     }
    33     
    34 }
    35 class Student extends Person
    36 {
    37     public Student() {
    38         super();
    39     }
    40     public Student(String name, String age) {
    41         super(name, age);
    42     }
    43     @Override
    44     public String toString() {
    45         return "Student [toString()=" + super.toString() + "]
    ";
    46     }
    47     
    48 }
    49 class Worker extends Person
    50 {
    51     public Worker() {
    52         super();
    53     }
    54     public Worker(String name, String age) {
    55         super(name, age);
    56     }
    57     @Override
    58     public String toString() {
    59         return "Worker [toString()=" + super.toString() + "]
    ";
    60     }
    61     
    62 }
    63 class Tool
    64 {
    65     public Object p;
    66     public Tool(Object p) {
    67         super();
    68         this.p = p;
    69     }
    70     public Tool() {
    71         super();
    72     }
    73     public Object getP() {
    74         return p;
    75     }
    76     public void setP(Object p) {
    77         this.p = p;
    78     }
    79 }
    80 public class GenerateClassDemo {
    81     public static void main(String args[])
    82     {
    83         Tool tool=new Tool();
    84         tool.setP(new Student("张三","23"));
    85         Student stu=(Student)tool.getP();
    86         System.out.println(stu);
    87         
    88         tool.setP(new Worker("李四","24"));
    89         stu=(Student)tool.getP();
    90         System.out.println(stu);
    91     }
    92 }
    View Code

    分析:装错了对象,即不应当装Worker类的对象,这在编译时期就应当注意到。

    在JDK1.5之后,使用泛型来接受类中要操作的引用数据类型。
    泛型类:当类中操作的引用数据类型不确定的时候就使用泛型来表示。
    解决方法:改进Tool类,使用泛型类 class Tool<T>

     1 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
     2 /*
     3  * 出现的问题。取出对象的时候出现了ClassCastException异常。
     4  */
     5 class Person
     6 {
     7     private String name;
     8     private String age;
     9     public Person() {
    10         super();
    11     }
    12     public Person(String name, String age) {
    13         super();
    14         this.name = name;
    15         this.age = age;
    16     }
    17     public String getName() {
    18         return name;
    19     }
    20     public void setName(String name) {
    21         this.name = name;
    22     }
    23     public String getAge() {
    24         return age;
    25     }
    26     public void setAge(String age) {
    27         this.age = age;
    28     }
    29     @Override
    30     public String toString() {
    31         return "Person [name=" + name + ", age=" + age + "]
    ";
    32     }
    33     
    34 }
    35 class Student extends Person
    36 {
    37     public Student() {
    38         super();
    39     }
    40     public Student(String name, String age) {
    41         super(name, age);
    42     }
    43     @Override
    44     public String toString() {
    45         return "Student [toString()=" + super.toString() + "]
    ";
    46     }
    47     
    48 }
    49 class Worker extends Person
    50 {
    51     public Worker() {
    52         super();
    53     }
    54     public Worker(String name, String age) {
    55         super(name, age);
    56     }
    57     @Override
    58     public String toString() {
    59         return "Worker [toString()=" + super.toString() + "]
    ";
    60     }
    61     
    62 }
    63 class Tool<T>
    64 {
    65     public T p;
    66     public Tool(T p) {
    67         super();
    68         this.p = p;
    69     }
    70     public Tool() {
    71         super();
    72     }
    73     public T getP() {
    74         return p;
    75     }
    76     public void setP(T p) {
    77         this.p = p;
    78     }
    79 }
    80 public class GenerateClassDemo {
    81     public static void main(String args[])
    82     {
    83         Tool<Student> tool=new Tool<Student>();
    84         tool.setP(new Student("张三","23"));
    85         Student stu=(Student)tool.getP();
    86         System.out.println(stu);
    87         
    88         tool.setP(new Worker("李四","24"));
    89         stu=(Student)tool.getP();
    90         System.out.println(stu);
    91     }
    92 }
    View Code

    这段代码不会编译成功,Eclipse会报错,这样就将运行时的问题转移到了编译时期。

    但是应当注意,如果在创建Tool对象的时候使用了Person类作为泛型类型,即使你只想要装Student对象,但是如果你一不小心装上了Worker对象,Eclipse也不会报错,原因很明显,不赘述,但是应当注意,这时候发生的错误就不是“失误”了,而是纯碎的逻辑错误了。

    使用Person类,Eclipse不会报错,但是在运行的时候会抛出classCastException异常。

     1 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
     2 /*
     3  * 出现的问题。取出对象的时候出现了ClassCastException异常。
     4  */
     5 class Person
     6 {
     7     private String name;
     8     private String age;
     9     public Person() {
    10         super();
    11     }
    12     public Person(String name, String age) {
    13         super();
    14         this.name = name;
    15         this.age = age;
    16     }
    17     public String getName() {
    18         return name;
    19     }
    20     public void setName(String name) {
    21         this.name = name;
    22     }
    23     public String getAge() {
    24         return age;
    25     }
    26     public void setAge(String age) {
    27         this.age = age;
    28     }
    29     @Override
    30     public String toString() {
    31         return "Person [name=" + name + ", age=" + age + "]
    ";
    32     }
    33     
    34 }
    35 class Student extends Person
    36 {
    37     public Student() {
    38         super();
    39     }
    40     public Student(String name, String age) {
    41         super(name, age);
    42     }
    43     @Override
    44     public String toString() {
    45         return "Student [toString()=" + super.toString() + "]
    ";
    46     }
    47     
    48 }
    49 class Worker extends Person
    50 {
    51     public Worker() {
    52         super();
    53     }
    54     public Worker(String name, String age) {
    55         super(name, age);
    56     }
    57     @Override
    58     public String toString() {
    59         return "Worker [toString()=" + super.toString() + "]
    ";
    60     }
    61     
    62 }
    63 class Tool<T>
    64 {
    65     public T p;
    66     public Tool(T p) {
    67         super();
    68         this.p = p;
    69     }
    70     public Tool() {
    71         super();
    72     }
    73     public T getP() {
    74         return p;
    75     }
    76     public void setP(T p) {
    77         this.p = p;
    78     }
    79 }
    80 public class GenerateClassDemo {
    81     public static void main(String args[])
    82     {
    83         Tool<Student> tool=new Tool<Student>();
    84         tool.setP(new Student("张三","23"));
    85         Student stu=(Student)tool.getP();
    86         System.out.println(stu);
    87         
    88         tool.setP(new Worker("李四","24"));
    89         stu=(Student)tool.getP();
    90         System.out.println(stu);
    91     }
    92 }
    View Code

    3.泛型方法。

    在方法上定义泛型应当将泛型放在返回值之前,修饰符之后。

    前者是定义泛型,后者是使用泛型。

    泛型方法分为非静态泛型方法和静态泛型方法。

    改造Tool类,使得Tool类能够使用show方法show出任意类型。分别使用非静态方法和静态方法的泛型表示形式。需要注意区别的是,静态方法的泛型只能加在方法上,即静态泛型方法不能访问类上定义的泛型,原因很明显,略。

      1 package p04.GenerateTypeDemo.Demo04.GenerateFunctionDemo01;
      2 
      3 /*
      4  * 泛型方法示例。
      5  */
      6 class Person
      7 {
      8     private String name;
      9     private String age;
     10     public Person() {
     11         super();
     12     }
     13     public Person(String name, String age) {
     14         super();
     15         this.name = name;
     16         this.age = age;
     17     }
     18     public String getName() {
     19         return name;
     20     }
     21     public void setName(String name) {
     22         this.name = name;
     23     }
     24     public String getAge() {
     25         return age;
     26     }
     27     public void setAge(String age) {
     28         this.age = age;
     29     }
     30     @Override
     31     public String toString() {
     32         return "Person [name=" + name + ", age=" + age + "]
    ";
     33     }
     34     
     35 }
     36 class Student extends Person
     37 {
     38     public Student() {
     39         super();
     40     }
     41     public Student(String name, String age) {
     42         super(name, age);
     43     }
     44     @Override
     45     public String toString() {
     46         return "Student [toString()=" + super.toString() + "]
    ";
     47     }
     48     
     49 }
     50 class Worker extends Person
     51 {
     52     public Worker() {
     53         super();
     54     }
     55     public Worker(String name, String age) {
     56         super(name, age);
     57     }
     58     @Override
     59     public String toString() {
     60         return "Worker [toString()=" + super.toString() + "]
    ";
     61     }
     62     
     63 }
     64 class Tool<T>
     65 {
     66     public T p;
     67     public Tool(T p) {
     68         super();
     69         this.p = p;
     70     }
     71     public Tool() {
     72         super();
     73     }
     74     public <W>void show(W w)//如果不是泛型方法,则应当注意泛型只能使用类提供的泛型
     75     {
     76         System.out.println(w);
     77     }
     78     public static<Q>void show_1(Q q)//静态方法的泛型必须加在方法上
     79     {
     80         System.out.println(q);
     81     }
     82     public T getP() {
     83         return p;
     84     }
     85     public void setP(T p) {
     86         this.p = p;
     87     }
     88 }
     89 public class GnerateFunctionDemo {
     90     
     91     public static void main(String args[])
     92     {
     93         Tool <Student>tool=new Tool<Student>();
     94         Student stu=new Student("zhangsan","23");
     95         tool.show(stu);
     96         
     97         tool.show(new Worker("lisi","24"));
     98         tool.show(new Worker("wangwu","25"));
     99     }
    100     
    101 
    102 }
    View Code

    4.泛型接口。

    泛型接口的定义很简单,和泛型类的定义几乎相同。

    实现泛型接口的类可以明确要使用的类型,也可以不明确要使用的类型,如果实现泛型接口的时候还不明确要使用的类型,则此类将是泛型类。

    下面分别演示两种实现类。

     1 package p04.GenerateTypeDemo.Demo05.GenerateInterfaceDemo01;
     2 
     3 /*
     4  * 泛型接口。
     5  */
     6 interface Inter<T>
     7 {
     8      public void show(T t);
     9 }
    10  class InterImpl implements Inter<String>//确定了类型的实现类
    11  {
    12     @Override
    13     public void show(String t) {
    14         System.out.println(t);
    15     }
    16  }
    17  class InterImpll <Q>implements Inter<Q>//不确定类型的实现类。
    18     {
    19         @Override
    20         public void show(Q t) {
    21             System.out.println(t);
    22         }
    23     }
    24 public class GenerateInterfaceDemo01 {
    25     public static void main(String args[])
    26     {
    27         InterImpl ii=new InterImpl();
    28         ii.show(new String("zhangsan"));
    29         
    30         InterImpll<String> iil=new  InterImpll<String>();
    31         iil.show(new Integer("123").toString());
    32         
    33     }
    34 }
    View Code

     三、泛型的上限和下限

    1.泛型的通配符?

    ?是泛型的通配符,作用和E相似,都代表了不确定的类型。

    可以使用以下代码遍历容器:单独的一个?代表着? extends Object

    1 public static void Traversal03(Collection<?>coll)
    2     {
    3         for(Iterator<?>it=coll.iterator();it.hasNext();)
    4         {
    5             System.out.println(it.next());
    6         }
    7     }
    View Code

    也可以使用泛型方法遍历容器:

    1 public static<E> void Traversal04(Collection<E>coll)
    2     {
    3         for(Iterator<E>it=coll.iterator();it.hasNext();)
    4         {
    5             System.out.println(it.next());
    6         }
    7     }
    View Code

    以上两个代码作用是完全相同的,但是使用泛型方法更有优势:可以将对象取出来并加以其它操作,所以使用泛型方法的情况比较多。

    1 public static<E> void Traversal05(Collection<E>coll)
    2     {
    3         for(Iterator<E>it=coll.iterator();;)
    4         {
    5             E e=it.next();
    6             System.out.println(e);
    7         }
    8     }
    View Code

    2.泛型的上限

    现在有两个ArrayList容器分别存储Person类对象和Student类对象,如果想要迭代两个容器,该怎么做?如果迭代的方法参数中接收的类型是Collection<Person>则会在

            print(al1);

    报错。

     1 package p04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Collection;
     5 
     6 class Person
     7 {
     8     private String name;
     9     private int age;
    10     
    11     public Person() {
    12         super();
    13     }
    14     public Person(String name, int age) {
    15         super();
    16         this.name = name;
    17         this.age = age;
    18     }
    19     public String getName() {
    20         return name;
    21     }
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25     public int getAge() {
    26         return age;
    27     }
    28     public void setAge(int age) {
    29         this.age = age;
    30     }
    31     
    32 }
    33 class Student extends Person
    34 {
    35 
    36     public Student() {
    37         super();
    38     }
    39 
    40     public Student(String name, int age) {
    41         super(name, age);
    42     }
    43     
    44 }
    45 class Worker extends Person
    46 {
    47 
    48     public Worker() {
    49         super();
    50     }
    51 
    52     public Worker(String name, int age) {
    53         super(name, age);
    54     }
    55     
    56 }
    57 public class GenerateUpperLimitDemo {
    58     public static void main(String args[])
    59     {
    60         ArrayList <Person>al=new  ArrayList<Person>();
    61         al.add(new Person("zhangsan",23));
    62         al.add(new Person("lisi",24));
    63         print(al);
    64         
    65         ArrayList<Student>al1=new ArrayList<Student>();
    66         al1.add(new Student("wangwu",25));
    67         al1.add(new Student("zhaoliu",26));
    68         print(al1);
    69     }
    70 
    71     private static void print(Collection<Person> al)
    72     {
    73         
    74     }
    75 
    76 }
    View Code

    报错的原因是泛型类型不匹配,相当于代码Collection<Person>col=new ArrayList<Student>();

    解决方法:使用泛型的上限。

    使用方法:? extends XXX,代表着可以接受XXX类的对象和XXX类的子类对象。

     1 package p04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Collection;
     5 import java.util.Iterator;
     6 
     7 class Person
     8 {
     9     private String name;
    10     private int age;
    11     
    12     public Person() {
    13         super();
    14     }
    15     public Person(String name, int age) {
    16         super();
    17         this.name = name;
    18         this.age = age;
    19     }
    20     public String getName() {
    21         return name;
    22     }
    23     public void setName(String name) {
    24         this.name = name;
    25     }
    26     public int getAge() {
    27         return age;
    28     }
    29     public void setAge(int age) {
    30         this.age = age;
    31     }
    32     
    33 }
    34 class Student extends Person
    35 {
    36 
    37     public Student() {
    38         super();
    39     }
    40 
    41     public Student(String name, int age) {
    42         super(name, age);
    43     }
    44     
    45 }
    46 class Worker extends Person
    47 {
    48 
    49     public Worker() {
    50         super();
    51     }
    52 
    53     public Worker(String name, int age) {
    54         super(name, age);
    55     }
    56     
    57 }
    58 public class GenerateUpperLimitDemo {
    59     public static void main(String args[])
    60     {
    61         ArrayList <Person>al=new  ArrayList<Person>();
    62         al.add(new Person("zhangsan",23));
    63         al.add(new Person("lisi",24));
    64         print(al);
    65         
    66         ArrayList<Student>al1=new ArrayList<Student>();
    67         al1.add(new Student("wangwu",25));
    68         al1.add(new Student("zhaoliu",26));
    69         print(al1);
    70     }
    71 
    72     private static void print(Collection<? extends Person> al)
    73     {
    74         for(Iterator<? extends Person>it=al.iterator();it.hasNext();)
    75         {
    76             Person p=it.next();
    77             System.out.println(p.getName()+":"+p.getAge());
    78         }
    79     }
    80 
    81 }
    View Code

    其中,这段代码是重点:

    1 private static void print(Collection<? extends Person> al)
    2     {
    3         for(Iterator<? extends Person>it=al.iterator();it.hasNext();)
    4         {
    5             Person p=it.next();
    6             System.out.println(p.getName()+":"+p.getAge());
    7         }
    8     }
    View Code

    这段代码可以使用泛型方法或者一个泛型通配符来解决,但是这样做并不如使用泛型的上限效果好。

    使用上限有什么好处?

    (1)可以明确一个具体的父类,这样就可以拿到父类中的所有方法。

    (2)可以限定可以接受的参数范围,而不是所有的类型(相对于普通的泛型方法)

    3.泛型的下限。

    用法:? super XXX;表示可以接受的参数范围包括XXX类以及XXX类的父类。

    举例:

      1 package p04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;
      2 
      3 import java.util.Comparator;
      4 import java.util.TreeSet;
      5 
      6 class Person implements Comparable<Person>
      7 {
      8     private String name;
      9     private int age;
     10     
     11     @Override
     12     public String toString() {
     13         return "Person [name=" + name + ", age=" + age + "]
    ";
     14     }
     15     public Person() {
     16         super();
     17     }
     18     public Person(String name, int age) {
     19         super();
     20         this.name = name;
     21         this.age = age;
     22     }
     23     public String getName() {
     24         return name;
     25     }
     26     public void setName(String name) {
     27         this.name = name;
     28     }
     29     public int getAge() {
     30         return age;
     31     }
     32     public void setAge(int age) {
     33         this.age = age;
     34     }
     35     @Override
     36     public int compareTo(Person o) {
     37         int temp=this.age-o.getAge();
     38         return temp==0?this.name.compareTo(o.getName()):temp;
     39     }
     40 }
     41 class Student extends Person
     42 {
     43 
     44     public Student() {
     45         super();
     46     }
     47 
     48     public Student(String name, int age) {
     49         super(name, age);
     50     }
     51     
     52 }
     53 class Worker extends Person
     54 {
     55 
     56     public Worker() {
     57         super();
     58     }
     59 
     60     public Worker(String name, int age) {
     61         super(name, age);
     62     }
     63     
     64 }
     65 public class GnerateDownLimitDemo {
     66     public static void main(String args[])
     67     {
     68         //Demo1();
     69         Demo2();
     70     }
     71 
     72 /*
     73  * 该方法演示传入父类比较器仍然能够正常添加元素
     74  */
     75     private static void Demo2() {
     76         TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByAny());
     77         ts.add(new Student("zhangsan",23));
     78         ts.add(new Student("lisi",24));
     79         System.out.println(ts);
     80         
     81         TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByAny());
     82         tst.add(new Worker("zhaoliu",26));
     83         tst.add(new Worker("wangwu",25));
     84         System.out.println(tst);
     85         
     86     }
     87 
     88     private static void Demo1() {
     89         TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByStudent());
     90         ts.add(new Student("zhangsan",23));
     91         ts.add(new Student("lisi",24));
     92         System.out.println(ts);
     93         
     94         TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByWorker());
     95         tst.add(new Worker("zhaoliu",26));
     96         tst.add(new Worker("wangwu",25));
     97         System.out.println(tst);
     98     }
     99 }
    100 class ComparatorByStudent implements Comparator<Student>
    101 {
    102 
    103     @Override
    104     public int compare(Student o1, Student o2) {
    105         int temp=o1.getName().compareTo(o2.getName());
    106         return temp==0?o1.getAge()-o2.getAge():temp;
    107     }
    108     
    109 }
    110 class ComparatorByWorker implements Comparator<Worker>
    111 {
    112     @Override
    113     public int compare(Worker o1, Worker o2) {
    114         int temp=o1.getName().compareTo(o2.getName());
    115         return temp==0?o1.getAge()-o2.getAge():temp;
    116     }
    117 }
    118 class ComparatorByAny implements Comparator<Person>
    119 {
    120     @Override
    121     public int compare(Person o1, Person o2) {
    122         int temp=o1.getName().compareTo(o2.getName());
    123         return temp==0?o1.getAge()-o2.getAge():temp;
    124     }
    125     
    126 }
    View Code

    4.泛型上限的体现。

    Collection类的addAll方法:

     boolean addAll(Collection<? extends E> c)
              将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。

    为什么在这里要使用泛型的上限?

    为了增强扩展性。上限一般在存储元素的时候使用,表示无论是E类型还是E的子类型,都可以存入容器,而取出的时候统一使用E类型取出,这样不会出现类型安全隐患。反之,如果不加限定,取出的时候就很困难了。事实上这里使用一个E就可以了,但是考虑到扩展性,使用了泛型的上限。

    上限的使用比较多一些(相对于下限)。

    5.泛型下限的体现。

    TreeSet的一个构造方法使用了泛型的下限:

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

     

     实例:

      1 package p04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Collection;
      5 import java.util.Comparator;
      6 import java.util.Iterator;
      7 import java.util.TreeSet;
      8 
      9 class Person implements Comparable<Person>
     10 {
     11     private String name;
     12     private int age;
     13     
     14     @Override
     15     public String toString() {
     16         return "Person [name=" + name + ", age=" + age + "]
    ";
     17     }
     18     public Person() {
     19         super();
     20     }
     21     public Person(String name, int age) {
     22         super();
     23         this.name = name;
     24         this.age = age;
     25     }
     26     public String getName() {
     27         return name;
     28     }
     29     public void setName(String name) {
     30         this.name = name;
     31     }
     32     public int getAge() {
     33         return age;
     34     }
     35     public void setAge(int age) {
     36         this.age = age;
     37     }
     38     @Override
     39     public int compareTo(Person o) {
     40         int temp=this.age-o.getAge();
     41         return temp==0?this.name.compareTo(o.getName()):temp;
     42     }
     43 }
     44 class Student extends Person
     45 {
     46 
     47     public Student() {
     48         super();
     49     }
     50 
     51     public Student(String name, int age) {
     52         super(name, age);
     53     }
     54     
     55 }
     56 class Worker extends Person
     57 {
     58 
     59     public Worker() {
     60         super();
     61     }
     62 
     63     public Worker(String name, int age) {
     64         super(name, age);
     65     }
     66     
     67 }
     68 public class GnerateDownLimitDemo {
     69     public static void main(String args[])
     70     {
     71         //Demo1();
     72         Demo2();
     73     }
     74 /*
     75  * 该方法演示传入
     76  */
     77     private static void Demo2() {
     78         TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByAny());
     79         ts.add(new Student("zhangsan",23));
     80         ts.add(new Student("lisi",24));
     81         System.out.println(ts);
     82         
     83         TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByAny());
     84         tst.add(new Worker("zhaoliu",26));
     85         tst.add(new Worker("wangwu",25));
     86         System.out.println(tst);
     87         
     88     }
     89 
     90     private static void Demo1() {
     91         TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByStudent());
     92         ts.add(new Student("zhangsan",23));
     93         ts.add(new Student("lisi",24));
     94         System.out.println(ts);
     95         
     96         TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByWorker());
     97         tst.add(new Worker("zhaoliu",26));
     98         tst.add(new Worker("wangwu",25));
     99         System.out.println(tst);
    100     }
    101 }
    102 class ComparatorByStudent implements Comparator<Student>
    103 {
    104 
    105     @Override
    106     public int compare(Student o1, Student o2) {
    107         int temp=o1.getName().compareTo(o2.getName());
    108         return temp==0?o1.getAge()-o2.getAge():temp;
    109     }
    110     
    111 }
    112 class ComparatorByWorker implements Comparator<Worker>
    113 {
    114     @Override
    115     public int compare(Worker o1, Worker o2) {
    116         int temp=o1.getName().compareTo(o2.getName());
    117         return temp==0?o1.getAge()-o2.getAge():temp;
    118     }
    119 }
    120 class ComparatorByAny implements Comparator<Person>
    121 {
    122     @Override
    123     public int compare(Person o1, Person o2) {
    124         int temp=o1.getName().compareTo(o2.getName());
    125         return temp==0?o1.getAge()-o2.getAge():temp;
    126     }
    127     
    128 }
    View Code

    在这个例子中,比较器只接受Person类型的,但是装有Student对象的TreeSet容器以及装有Worker对象的TreeSet容器都可以使用这个比较器。这是因为TreeSet的构造方法中明确了比较器中可以接受的参数范围包括E类型以及E的父类型。所以,当插入Student对象的时候,虽然使用了Person的比较器,但是由于Person是Student的父类,满足? super Student条件,所以可以进行比较并成功插入;Worker同理。

    使用了泛型的下限,则只能接受E以及E的父类型。

    6.通配符的体现。

    List接口中的方法:

     boolean removeAll(Collection<?> c)
              从列表中移除指定 collection 中包含的其所有元素(可选操作)。
     boolean retainAll(Collection<?> c)
              仅在列表中保留指定 collection 中所包含的元素(可选操作)。

    为什么要使用'?'?

    我们要知道List接口中的removeAll方法和retainAll方法底层使用的都是equals方法,使用的参数是Object类型的,所以可以传入各种类型的参数,所以实际参数类型不确定,所以使用?。

  • 相关阅读:
    Django项目:CRM(客户关系管理系统)--54--45PerfectCRM实现账号快速重置密码
    Django项目:CRM(客户关系管理系统)--53--44PerfectCRM实现账号快速注册登陆
    Python 原生2种 邮件发送(发送验证码) 的方法
    Django项目:CRM(客户关系管理系统)--52--43PerfectCRM实现AJAX全局账号登陆
    Django项目:CRM(客户关系管理系统)--51--42PerfectCRM实现AJAX全局账号注册
    Django项目:CRM(客户关系管理系统)--50--41PerfectCRM实现全局账号密码修改
    Django项目:CRM(客户关系管理系统)--49--40PerfectCRM实现全局账号注册+验证码+页面刷新保留信息
    Django项目:CRM(客户关系管理系统)--48--39PerfectCRM实现登录+验证码+过期时间+页面保留账号
    mvc 伪静态任意扩展名的实现方法
    asp.net mvc各种传值方式大全
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4014207.html
Copyright © 2020-2023  润新知