【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类型的,所以可以传入各种类型的参数,所以实际参数类型不确定,所以使用?。

原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4014207.html