java实现字典用泛型_【JAVA之泛型】

一、引例。

1.引例。

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo01;2

3 importjava.util.ArrayList;4 importjava.util.ListIterator;5

6 public classDemo01 {7 public static voidmain(String args[])8 {9 ArrayList al=newArrayList();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之后就为此而产生了。

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

更改代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo01;2

3 importjava.util.ArrayList;4 importjava.util.ListIterator;5

6 public classDemo01 {7 public static voidmain(String args[])8 {9 ArrayListal=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中还没有运行就已经报错了。

f319d4663e90ef4c4bfedc7f0c73fef6.png

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo01;2

3 importjava.util.ArrayList;4 importjava.util.ListIterator;5

6 public classDemo01 {7 public static voidmain(String args[])8 {9 ArrayListal=new ArrayList();10 al.add("abc1");11 al.add("abc2");12 al.add("abc3");13 al.add("abc4");14 ListIterator 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中的常用使用方法:

按照年龄排序:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo02.TreeSetDemo;2

3 importjava.util.Iterator;4 importjava.util.TreeSet;5

6 class Person implements Comparable

7 {8 privateString name;9 private intage;10

11 publicPerson() {12 super();13 }14 public Person(String name, intage) {15 super();16 this.name =name;17 this.age =age;18 }19 @Override20 public inthashCode() {21 final int prime = 31;22 int result = 1;23 result = prime * result +age;24 result = prime * result + ((name == null) ? 0: name.hashCode());25 returnresult;26 }27 @Override28 public booleanequals(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 @Override46 publicString toString() {47 return "Person [name=" + name + ", age=" + age + "]\n";48 }49 publicString getName() {50 returnname;51 }52 public voidsetName(String name) {53 this.name =name;54 }55 public intgetAge() {56 returnage;57 }58 public void setAge(intage) {59 this.age =age;60 }61 @Override62 public intcompareTo(Person o) {63 //建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。

64 int temp=this.age-o.getAge();65 return temp==0?this.name.compareTo(o.getName()):temp;66 }67 }68 public classTreeSetDemo {69

70 public static voidmain(String[] args) {71 TreeSet ts=new TreeSet();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(Iteratorit=ts.iterator();it.hasNext();)79 {80 Person p=it.next();81 System .out.println(p);82 }83

84 }85

86 }

View Code

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo02.TreeSetDemo02;2

3 importjava.util.Comparator;4 importjava.util.Iterator;5 importjava.util.TreeSet;6

7 class Person implements Comparable

8 {9 privateString name;10 private intage;11

12 publicPerson() {13 super();14 }15 public Person(String name, intage) {16 super();17 this.name =name;18 this.age =age;19 }20 @Override21 public inthashCode() {22 final int prime = 31;23 int result = 1;24 result = prime * result +age;25 result = prime * result + ((name == null) ? 0: name.hashCode());26 returnresult;27 }28 @Override29 public booleanequals(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 @Override47 publicString toString() {48 return "Person [name=" + name + ", age=" + age + "]\n";49 }50 publicString getName() {51 returnname;52 }53 public voidsetName(String name) {54 this.name =name;55 }56 public intgetAge() {57 returnage;58 }59 public void setAge(intage) {60 this.age =age;61 }62 @Override63 public intcompareTo(Person o) {64 //建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。

65 int temp=this.age-o.getAge();66 return temp==0?this.name.compareTo(o.getName()):temp;67 }68 }69 public classTreeSetDemo {70

71 public static voidmain(String[] args) {72 TreeSet ts=new TreeSet(newComparatorByName());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(TreeSetts) {83 for(Iteratorit=ts.iterator();it.hasNext();)84 {85 Person p=it.next();86 System .out.println(p);87 }88 }89

90 }91 class ComparatorByName implements Comparator

92 {93 @Override94 public intcompare(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。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo03.GenerateClassDemo01;2 /*

3 * 出现的问题。取出对象的时候出现了ClassCastException异常。4 */

5 classPerson6 {7 privateString name;8 privateString age;9 publicPerson() {10 super();11 }12 publicPerson(String name, String age) {13 super();14 this.name =name;15 this.age =age;16 }17 publicString getName() {18 returnname;19 }20 public voidsetName(String name) {21 this.name =name;22 }23 publicString getAge() {24 returnage;25 }26 public voidsetAge(String age) {27 this.age =age;28 }29 @Override30 publicString toString() {31 return "Person [name=" + name + ", age=" + age + "]\n";32 }33

34 }35 class Student extendsPerson36 {37 publicStudent() {38 super();39 }40 publicStudent(String name, String age) {41 super(name, age);42 }43 @Override44 publicString toString() {45 return "Student [toString()=" + super.toString() + "]\n";46 }47

48 }49 class Worker extendsPerson50 {51 publicWorker() {52 super();53 }54 publicWorker(String name, String age) {55 super(name, age);56 }57 @Override58 publicString toString() {59 return "Worker [toString()=" + super.toString() + "]\n";60 }61

62 }63 classTool64 {65 publicObject p;66 publicTool(Object p) {67 super();68 this.p =p;69 }70 publicTool() {71 super();72 }73 publicObject getP() {74 returnp;75 }76 public voidsetP(Object p) {77 this.p =p;78 }79 }80 public classGenerateClassDemo {81 public static voidmain(String args[])82 {83 Tool tool=newTool();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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo03.GenerateClassDemo01;2 /*

3 * 出现的问题。取出对象的时候出现了ClassCastException异常。4 */

5 classPerson6 {7 privateString name;8 privateString age;9 publicPerson() {10 super();11 }12 publicPerson(String name, String age) {13 super();14 this.name =name;15 this.age =age;16 }17 publicString getName() {18 returnname;19 }20 public voidsetName(String name) {21 this.name =name;22 }23 publicString getAge() {24 returnage;25 }26 public voidsetAge(String age) {27 this.age =age;28 }29 @Override30 publicString toString() {31 return "Person [name=" + name + ", age=" + age + "]\n";32 }33

34 }35 class Student extendsPerson36 {37 publicStudent() {38 super();39 }40 publicStudent(String name, String age) {41 super(name, age);42 }43 @Override44 publicString toString() {45 return "Student [toString()=" + super.toString() + "]\n";46 }47

48 }49 class Worker extendsPerson50 {51 publicWorker() {52 super();53 }54 publicWorker(String name, String age) {55 super(name, age);56 }57 @Override58 publicString toString() {59 return "Worker [toString()=" + super.toString() + "]\n";60 }61

62 }63 class Tool

64 {65 publicT p;66 publicTool(T p) {67 super();68 this.p =p;69 }70 publicTool() {71 super();72 }73 publicT getP() {74 returnp;75 }76 public voidsetP(T p) {77 this.p =p;78 }79 }80 public classGenerateClassDemo {81 public static voidmain(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

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

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo03.GenerateClassDemo01;2 /*

3 * 出现的问题。取出对象的时候出现了ClassCastException异常。4 */

5 classPerson6 {7 privateString name;8 privateString age;9 publicPerson() {10 super();11 }12 publicPerson(String name, String age) {13 super();14 this.name =name;15 this.age =age;16 }17 publicString getName() {18 returnname;19 }20 public voidsetName(String name) {21 this.name =name;22 }23 publicString getAge() {24 returnage;25 }26 public voidsetAge(String age) {27 this.age =age;28 }29 @Override30 publicString toString() {31 return "Person [name=" + name + ", age=" + age + "]\n";32 }33

34 }35 class Student extendsPerson36 {37 publicStudent() {38 super();39 }40 publicStudent(String name, String age) {41 super(name, age);42 }43 @Override44 publicString toString() {45 return "Student [toString()=" + super.toString() + "]\n";46 }47

48 }49 class Worker extendsPerson50 {51 publicWorker() {52 super();53 }54 publicWorker(String name, String age) {55 super(name, age);56 }57 @Override58 publicString toString() {59 return "Worker [toString()=" + super.toString() + "]\n";60 }61

62 }63 class Tool

64 {65 publicT p;66 publicTool(T p) {67 super();68 this.p =p;69 }70 publicTool() {71 super();72 }73 publicT getP() {74 returnp;75 }76 public voidsetP(T p) {77 this.p =p;78 }79 }80 public classGenerateClassDemo {81 public static voidmain(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

3.泛型方法。

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

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

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo04.GenerateFunctionDemo01;2

3 /*

4 * 泛型方法示例。5 */

6 classPerson7 {8 privateString name;9 privateString age;10 publicPerson() {11 super();12 }13 publicPerson(String name, String age) {14 super();15 this.name =name;16 this.age =age;17 }18 publicString getName() {19 returnname;20 }21 public voidsetName(String name) {22 this.name =name;23 }24 publicString getAge() {25 returnage;26 }27 public voidsetAge(String age) {28 this.age =age;29 }30 @Override31 publicString toString() {32 return "Person [name=" + name + ", age=" + age + "]\n";33 }34

35 }36 class Student extendsPerson37 {38 publicStudent() {39 super();40 }41 publicStudent(String name, String age) {42 super(name, age);43 }44 @Override45 publicString toString() {46 return "Student [toString()=" + super.toString() + "]\n";47 }48

49 }50 class Worker extendsPerson51 {52 publicWorker() {53 super();54 }55 publicWorker(String name, String age) {56 super(name, age);57 }58 @Override59 publicString toString() {60 return "Worker [toString()=" + super.toString() + "]\n";61 }62

63 }64 class Tool

65 {66 publicT p;67 publicTool(T p) {68 super();69 this.p =p;70 }71 publicTool() {72 super();73 }74 public void show(W w)//如果不是泛型方法,则应当注意泛型只能使用类提供的泛型

75 {76 System.out.println(w);77 }78 public staticvoid show_1(Q q)//静态方法的泛型必须加在方法上

79 {80 System.out.println(q);81 }82 publicT getP() {83 returnp;84 }85 public voidsetP(T p) {86 this.p =p;87 }88 }89 public classGnerateFunctionDemo {90

91 public static voidmain(String args[])92 {93 Tool tool=new Tool();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.泛型接口。

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

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo05.GenerateInterfaceDemo01;2

3 /*

4 * 泛型接口。5 */

6 interface Inter

7 {8 public voidshow(T t);9 }10 class InterImpl implements Inter//确定了类型的实现类

11 {12 @Override13 public voidshow(String t) {14 System.out.println(t);15 }16 }17 class InterImpll implements Inter//不确定类型的实现类。

18 {19 @Override20 public voidshow(Q t) {21 System.out.println(t);22 }23 }24 public classGenerateInterfaceDemo01 {25 public static voidmain(String args[])26 {27 InterImpl ii=newInterImpl();28 ii.show(new String("zhangsan"));29

30 InterImpll iil=new InterImpll();31 iil.show(new Integer("123").toString());32

33 }34 }

View Code

三、泛型的上限和下限

1.泛型的通配符?

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public static void Traversal04(Collectioncoll)2 {3 for(Iteratorit=coll.iterator();it.hasNext();)4 {5 System.out.println(it.next());6 }7 }

View Code

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public static void Traversal05(Collectioncoll)2 {3 for(Iteratorit=coll.iterator();;)4 {5 E e=it.next();6 System.out.println(e);7 }8 }

View Code

2.泛型的上限

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

print(al1);

报错。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;2

3 importjava.util.ArrayList;4 importjava.util.Collection;5

6 classPerson7 {8 privateString name;9 private intage;10

11 publicPerson() {12 super();13 }14 public Person(String name, intage) {15 super();16 this.name =name;17 this.age =age;18 }19 publicString getName() {20 returnname;21 }22 public voidsetName(String name) {23 this.name =name;24 }25 public intgetAge() {26 returnage;27 }28 public void setAge(intage) {29 this.age =age;30 }31

32 }33 class Student extendsPerson34 {35

36 publicStudent() {37 super();38 }39

40 public Student(String name, intage) {41 super(name, age);42 }43

44 }45 class Worker extendsPerson46 {47

48 publicWorker() {49 super();50 }51

52 public Worker(String name, intage) {53 super(name, age);54 }55

56 }57 public classGenerateUpperLimitDemo {58 public static voidmain(String args[])59 {60 ArrayList al=new ArrayList();61 al.add(new Person("zhangsan",23));62 al.add(new Person("lisi",24));63 print(al);64

65 ArrayListal1=new ArrayList();66 al1.add(new Student("wangwu",25));67 al1.add(new Student("zhaoliu",26));68 print(al1);69 }70

71 private static void print(Collectional)72 {73

74 }75

76 }

View Code

报错的原因是泛型类型不匹配,相当于代码Collectioncol=new ArrayList();

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;2

3 importjava.util.ArrayList;4 importjava.util.Collection;5 importjava.util.Iterator;6

7 classPerson8 {9 privateString name;10 private intage;11

12 publicPerson() {13 super();14 }15 public Person(String name, intage) {16 super();17 this.name =name;18 this.age =age;19 }20 publicString getName() {21 returnname;22 }23 public voidsetName(String name) {24 this.name =name;25 }26 public intgetAge() {27 returnage;28 }29 public void setAge(intage) {30 this.age =age;31 }32

33 }34 class Student extendsPerson35 {36

37 publicStudent() {38 super();39 }40

41 public Student(String name, intage) {42 super(name, age);43 }44

45 }46 class Worker extendsPerson47 {48

49 publicWorker() {50 super();51 }52

53 public Worker(String name, intage) {54 super(name, age);55 }56

57 }58 public classGenerateUpperLimitDemo {59 public static voidmain(String args[])60 {61 ArrayList al=new ArrayList();62 al.add(new Person("zhangsan",23));63 al.add(new Person("lisi",24));64 print(al);65

66 ArrayListal1=new ArrayList();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

其中,这段代码是重点:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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类的父类。

举例:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;2

3 importjava.util.Comparator;4 importjava.util.TreeSet;5

6 class Person implements Comparable

7 {8 privateString name;9 private intage;10

11 @Override12 publicString toString() {13 return "Person [name=" + name + ", age=" + age + "]\n";14 }15 publicPerson() {16 super();17 }18 public Person(String name, intage) {19 super();20 this.name =name;21 this.age =age;22 }23 publicString getName() {24 returnname;25 }26 public voidsetName(String name) {27 this.name =name;28 }29 public intgetAge() {30 returnage;31 }32 public void setAge(intage) {33 this.age =age;34 }35 @Override36 public intcompareTo(Person o) {37 int temp=this.age-o.getAge();38 return temp==0?this.name.compareTo(o.getName()):temp;39 }40 }41 class Student extendsPerson42 {43

44 publicStudent() {45 super();46 }47

48 public Student(String name, intage) {49 super(name, age);50 }51

52 }53 class Worker extendsPerson54 {55

56 publicWorker() {57 super();58 }59

60 public Worker(String name, intage) {61 super(name, age);62 }63

64 }65 public classGnerateDownLimitDemo {66 public static voidmain(String args[])67 {68 //Demo1();

69 Demo2();70 }71

72 /*

73 * 该方法演示传入父类比较器仍然能够正常添加元素74 */

75 private static voidDemo2() {76 TreeSet ts=new TreeSet(newComparatorByAny());77 ts.add(new Student("zhangsan",23));78 ts.add(new Student("lisi",24));79 System.out.println(ts);80

81 TreeSettst=new TreeSet(newComparatorByAny());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 voidDemo1() {89 TreeSet ts=new TreeSet(newComparatorByStudent());90 ts.add(new Student("zhangsan",23));91 ts.add(new Student("lisi",24));92 System.out.println(ts);93

94 TreeSettst=new TreeSet(newComparatorByWorker());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

101 {102

103 @Override104 public intcompare(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

111 {112 @Override113 public intcompare(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

119 {120 @Override121 public intcompare(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

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

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

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

5.泛型下限的体现。

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

Comparator super E> comparator)

构造一个新的空 TreeSet,它根据指定比较器进行排序。

实例:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagep04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;2

3 importjava.util.ArrayList;4 importjava.util.Collection;5 importjava.util.Comparator;6 importjava.util.Iterator;7 importjava.util.TreeSet;8

9 class Person implements Comparable

10 {11 privateString name;12 private intage;13

14 @Override15 publicString toString() {16 return "Person [name=" + name + ", age=" + age + "]\n";17 }18 publicPerson() {19 super();20 }21 public Person(String name, intage) {22 super();23 this.name =name;24 this.age =age;25 }26 publicString getName() {27 returnname;28 }29 public voidsetName(String name) {30 this.name =name;31 }32 public intgetAge() {33 returnage;34 }35 public void setAge(intage) {36 this.age =age;37 }38 @Override39 public intcompareTo(Person o) {40 int temp=this.age-o.getAge();41 return temp==0?this.name.compareTo(o.getName()):temp;42 }43 }44 class Student extendsPerson45 {46

47 publicStudent() {48 super();49 }50

51 public Student(String name, intage) {52 super(name, age);53 }54

55 }56 class Worker extendsPerson57 {58

59 publicWorker() {60 super();61 }62

63 public Worker(String name, intage) {64 super(name, age);65 }66

67 }68 public classGnerateDownLimitDemo {69 public static voidmain(String args[])70 {71 //Demo1();

72 Demo2();73 }74 /*

75 * 该方法演示传入76 */

77 private static voidDemo2() {78 TreeSet ts=new TreeSet(newComparatorByAny());79 ts.add(new Student("zhangsan",23));80 ts.add(new Student("lisi",24));81 System.out.println(ts);82

83 TreeSettst=new TreeSet(newComparatorByAny());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 voidDemo1() {91 TreeSet ts=new TreeSet(newComparatorByStudent());92 ts.add(new Student("zhangsan",23));93 ts.add(new Student("lisi",24));94 System.out.println(ts);95

96 TreeSettst=new TreeSet(newComparatorByWorker());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

103 {104

105 @Override106 public intcompare(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

113 {114 @Override115 public intcompare(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

121 {122 @Override123 public intcompare(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

boolean

为什么要使用'?'?

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值