一、引例。

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. }

虽然这个程序在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. }

这个代码相对上一个代码来说只是加入了泛型,其余均没有变化,但是在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. }

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 + "]\n";
  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. }

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

  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 + "]\n";
  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. }

注意点:

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

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 + "]\n";
  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() + "]\n";
  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() + "]\n";
  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. }

分析:装错了对象,即不应当装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 + "]\n";
  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() + "]\n";
  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() + "]\n";
  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. }

这段代码不会编译成功,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 + "]\n";
  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() + "]\n";
  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() + "]\n";
  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. }

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 + "]\n";
  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() + "]\n";
  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() + "]\n";
  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. }

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. }

 三、泛型的上限和下限

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. }

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

  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. }

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

  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. }

2.泛型的上限

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

  1. 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. }

报错的原因是泛型类型不匹配,相当于代码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. }

其中,这段代码是重点:

  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. }

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

使用上限有什么好处?

(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 + "]\n";
  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. }

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 + "]\n";
  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. }

在这个例子中,比较器只接受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类型的,所以可以传入各种类型的参数,所以实际参数类型不确定,所以使用?。

【JAVA之泛型】的更多相关文章

  1. [改善Java代码]Java的泛型是类型擦除的

    泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...

  2. Java 中泛型的全面解析(转)

    Java泛型(generics) 是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在J ...

  3. Java中泛型 类型擦除

    转自:Java中泛型是类型擦除的 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类 ...

  4. Java 泛型 Java使用泛型的意义

    Java 泛型 Java使用泛型的意义 @author ixenos 直接意义 在编译时保证类型安全 根本意义 a) 类型安全问题源自可复用性代码的设计,泛型保证了类型安全的复用模板 b) 使用复用性 ...

  5. 跟着刚哥梳理java知识点——泛型(十三)

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: public class GenericTest { public static void main(String[] a ...

  6. 【Java】泛型学习笔记

    参考书籍 <Java核心技术:卷1> 泛型, 先睹为快 先通过一个简单的例子说明下Java中泛型的用法: 泛型的基本形式类似于模板, 通过一个类型参数T, 你可以"私人定制&qu ...

  7. [转] Java 的泛型擦除和运行时泛型信息获取

    原文链接 https://my.oschina.net/lifany/blog/875769 前言 现在很多程序员都会在简历中写上精通 Java.但究竟怎样才算是精通 Java 呢?我觉得不仅要熟练掌 ...

  8. Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...

  9. 【译】9. Java反射——泛型

    原文地址:http://tutorials.jenkov.com/java-reflection/generics.html ===================================== ...

  10. Java“禁止”泛型数组

    Java“禁止”泛型数组 原文:https://blog.csdn.net/yi_Afly/article/details/52058708 1. 泛型定义泛型编程是一种通过参数化的方式将数据处理与数 ...

随机推荐

  1. (集成电路卡)ID卡

    IC卡(intergrated Circuit Card,集成电路卡),又称为智能卡,智慧卡,微电路卡,微芯片卡 等等. 它是将一个微电子芯片嵌入符合ISO 7816标准的卡基中,做成卡片形状. IC ...

  2. am335x UART1输入u-boot 调试信息代码修改

    AM335x 调试信息UART1输出代码修改1. 关于pin_mux  的配置代码修改位置:/board/forlinx/ok335x/mux.c void enable_uart0_pin_mux( ...

  3. 转:linux下bwa和samtools的安装与使用

    bwa的安装流程安装本软体总共需要完成以下两个软体的安装工作:1) BWA2) Samtools1.BWA的安装a.下载BWA (download from BWA Source Forge ) ht ...

  4. linux 编程环境搭建过程记录

    1, 安装centos 7 最小版  过程略 ...... 2, 安装桌面安装yum groupinstall "GNOME Desktop" 更新系统运行级别ln -sf /li ...

  5. 5.3(2)----机器人走方格2(CC150)

    这道题只需要把障碍点都设为0就可以了. public static int countWays(int[][] map,int x, int y){ if( x < 0 || y < 0) ...

  6. Eclipse不给提示no default proposals

    解决方法: (1),找到工程所在的workspace,删除.metadata配置文件. (2),启动eclipse,重新定位到先前的workspace目录置,重建同名工程(不要删除原来的工程,只要建立 ...

  7. PHP使用curl替代file_get_contents

    初学php的朋友们,很容易翻一个错误,在写采集程序或者调用api接口总会有线考虑到使用file_get_contents函数来或许内容,程序的访问量不大倒是没什么影响,但是访问量提升了那非常的悲剧了, ...

  8. js apply 和 call

    http://www.cnblogs.com/KeenLeung/archive/2012/11/19/2778229.html

  9. ASP.NET页面传值不使用QueryString

    ASP.NET页面传值不使用QueryString   Asp.net中的页面传值方法: 1         Url传值 特点:主要优点是实现起来非常简单,然而它的缺点是传递的值是会显示在浏览器的地址 ...

  10. 使用logrotate管理nginx日志文件

    本文转载自:http://linux008.blog.51cto.com/2837805/555829 描述:linux日志文件如果不定期清理,会填满整个磁盘.这样会很危险,因此日志管理是系统管理员日 ...