一、引例。

1.引例。

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

 package p04.GenerateTypeDemo.Demo01;

 import java.util.ArrayList;
import java.util.ListIterator; public class Demo01 {
public static void main(String args[])
{
ArrayList al=new ArrayList();
al.add("abc1");
al.add("abc2");
al.add(1);
al.add(2);
ListIterator li=al.listIterator();
while(li.hasNext())
{
String str=(String)li.next();
System.out.println(str);
}
} }

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

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

更改代码:

 package p04.GenerateTypeDemo.Demo01;

 import java.util.ArrayList;
import java.util.ListIterator; public class Demo01 {
public static void main(String args[])
{
ArrayList<String>al=new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add(1);
al.add(2);
ListIterator<String> li=al.listIterator();
while(li.hasNext())
{
String str=(String)li.next();
System.out.println(str);
}
} }

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

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

 package p04.GenerateTypeDemo.Demo01;

 import java.util.ArrayList;
import java.util.ListIterator; public class Demo01 {
public static void main(String args[])
{
ArrayList<String>al=new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
al.add("abc4");
ListIterator<String> li=al.listIterator();
while(li.hasNext())
{
String str=li.next();
System.out.println(str);
}
} }

2.总结:

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

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

使用泛型的好处:

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

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

解惑:<>和E

<>是什么?

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

<>什么时候用?

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

E是什么?

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

3.泛型的擦除和补偿。

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

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

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

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

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

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

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

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

按照年龄排序:

 package p04.GenerateTypeDemo.Demo02.TreeSetDemo;

 import java.util.Iterator;
import java.util.TreeSet; class Person implements Comparable<Person>
{
private String name;
private int age; public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
//建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
public class TreeSetDemo { public static void main(String[] args) {
TreeSet<Person> ts=new TreeSet<Person>();
ts.add(new Person("zhangsan",25));
ts.add(new Person("lisib",24));
ts.add(new Person("lisia",24));
ts.add(new Person("wangwu",29));
ts.add(new Person("zhaoliu",22)); for(Iterator<Person>it=ts.iterator();it.hasNext();)
{
Person p=it.next();
System .out.println(p);
} } }

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

 package p04.GenerateTypeDemo.Demo02.TreeSetDemo02;

 import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet; class Person implements Comparable<Person>
{
private String name;
private int age; public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
//建立排序规则,按照年龄进行整体排序,如果年龄相同,则按照姓名的字典序排序。
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
public class TreeSetDemo { public static void main(String[] args) {
TreeSet<Person> ts=new TreeSet<Person>(new ComparatorByName());
ts.add(new Person("zhangsan",25));
ts.add(new Person("lisib",24));
ts.add(new Person("lisia",24));
ts.add(new Person("wangwu",29));
ts.add(new Person("zhaoliu",22)); out(ts);
} private static void out(TreeSet<Person> ts) {
for(Iterator<Person>it=ts.iterator();it.hasNext();)
{
Person p=it.next();
System .out.println(p);
}
} }
class ComparatorByName implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
} }

注意点:

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

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

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

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

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

2.泛型类。

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

 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
/*
* 出现的问题。取出对象的时候出现了ClassCastException异常。
*/
class Person
{
private String name;
private String age;
public Person() {
super();
}
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
} }
class Student extends Person
{
public Student() {
super();
}
public Student(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Student [toString()=" + super.toString() + "]\n";
} }
class Worker extends Person
{
public Worker() {
super();
}
public Worker(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Worker [toString()=" + super.toString() + "]\n";
} }
class Tool
{
public Object p;
public Tool(Object p) {
super();
this.p = p;
}
public Tool() {
super();
}
public Object getP() {
return p;
}
public void setP(Object p) {
this.p = p;
}
}
public class GenerateClassDemo {
public static void main(String args[])
{
Tool tool=new Tool();
tool.setP(new Student("张三","23"));
Student stu=(Student)tool.getP();
System.out.println(stu); tool.setP(new Worker("李四","24"));
stu=(Student)tool.getP();
System.out.println(stu);
}
}

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

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

 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
/*
* 出现的问题。取出对象的时候出现了ClassCastException异常。
*/
class Person
{
private String name;
private String age;
public Person() {
super();
}
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
} }
class Student extends Person
{
public Student() {
super();
}
public Student(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Student [toString()=" + super.toString() + "]\n";
} }
class Worker extends Person
{
public Worker() {
super();
}
public Worker(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Worker [toString()=" + super.toString() + "]\n";
} }
class Tool<T>
{
public T p;
public Tool(T p) {
super();
this.p = p;
}
public Tool() {
super();
}
public T getP() {
return p;
}
public void setP(T p) {
this.p = p;
}
}
public class GenerateClassDemo {
public static void main(String args[])
{
Tool<Student> tool=new Tool<Student>();
tool.setP(new Student("张三","23"));
Student stu=(Student)tool.getP();
System.out.println(stu); tool.setP(new Worker("李四","24"));
stu=(Student)tool.getP();
System.out.println(stu);
}
}

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

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

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

 package p04.GenerateTypeDemo.Demo03.GenerateClassDemo01;
/*
* 出现的问题。取出对象的时候出现了ClassCastException异常。
*/
class Person
{
private String name;
private String age;
public Person() {
super();
}
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
} }
class Student extends Person
{
public Student() {
super();
}
public Student(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Student [toString()=" + super.toString() + "]\n";
} }
class Worker extends Person
{
public Worker() {
super();
}
public Worker(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Worker [toString()=" + super.toString() + "]\n";
} }
class Tool<T>
{
public T p;
public Tool(T p) {
super();
this.p = p;
}
public Tool() {
super();
}
public T getP() {
return p;
}
public void setP(T p) {
this.p = p;
}
}
public class GenerateClassDemo {
public static void main(String args[])
{
Tool<Student> tool=new Tool<Student>();
tool.setP(new Student("张三","23"));
Student stu=(Student)tool.getP();
System.out.println(stu); tool.setP(new Worker("李四","24"));
stu=(Student)tool.getP();
System.out.println(stu);
}
}

3.泛型方法。

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

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

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

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

 package p04.GenerateTypeDemo.Demo04.GenerateFunctionDemo01;

 /*
* 泛型方法示例。
*/
class Person
{
private String name;
private String age;
public Person() {
super();
}
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
} }
class Student extends Person
{
public Student() {
super();
}
public Student(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Student [toString()=" + super.toString() + "]\n";
} }
class Worker extends Person
{
public Worker() {
super();
}
public Worker(String name, String age) {
super(name, age);
}
@Override
public String toString() {
return "Worker [toString()=" + super.toString() + "]\n";
} }
class Tool<T>
{
public T p;
public Tool(T p) {
super();
this.p = p;
}
public Tool() {
super();
}
public <W>void show(W w)//如果不是泛型方法,则应当注意泛型只能使用类提供的泛型
{
System.out.println(w);
}
public static<Q>void show_1(Q q)//静态方法的泛型必须加在方法上
{
System.out.println(q);
}
public T getP() {
return p;
}
public void setP(T p) {
this.p = p;
}
}
public class GnerateFunctionDemo { public static void main(String args[])
{
Tool <Student>tool=new Tool<Student>();
Student stu=new Student("zhangsan","23");
tool.show(stu); tool.show(new Worker("lisi","24"));
tool.show(new Worker("wangwu","25"));
} }

4.泛型接口。

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

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

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

 package p04.GenerateTypeDemo.Demo05.GenerateInterfaceDemo01;

 /*
* 泛型接口。
*/
interface Inter<T>
{
public void show(T t);
}
class InterImpl implements Inter<String>//确定了类型的实现类
{
@Override
public void show(String t) {
System.out.println(t);
}
}
class InterImpll <Q>implements Inter<Q>//不确定类型的实现类。
{
@Override
public void show(Q t) {
System.out.println(t);
}
}
public class GenerateInterfaceDemo01 {
public static void main(String args[])
{
InterImpl ii=new InterImpl();
ii.show(new String("zhangsan")); InterImpll<String> iil=new InterImpll<String>();
iil.show(new Integer("123").toString()); }
}

 三、泛型的上限和下限

1.泛型的通配符?

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

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

 public static void Traversal03(Collection<?>coll)
{
for(Iterator<?>it=coll.iterator();it.hasNext();)
{
System.out.println(it.next());
}
}

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

 public static<E> void Traversal04(Collection<E>coll)
{
for(Iterator<E>it=coll.iterator();it.hasNext();)
{
System.out.println(it.next());
}
}

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

 public static<E> void Traversal05(Collection<E>coll)
{
for(Iterator<E>it=coll.iterator();;)
{
E e=it.next();
System.out.println(e);
}
}

2.泛型的上限

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

        print(al1);

报错。

 package p04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;

 import java.util.ArrayList;
import java.util.Collection; class Person
{
private String name;
private int age; public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }
class Student extends Person
{ public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} }
public class GenerateUpperLimitDemo {
public static void main(String args[])
{
ArrayList <Person>al=new ArrayList<Person>();
al.add(new Person("zhangsan",23));
al.add(new Person("lisi",24));
print(al); ArrayList<Student>al1=new ArrayList<Student>();
al1.add(new Student("wangwu",25));
al1.add(new Student("zhaoliu",26));
print(al1);
} private static void print(Collection<Person> al)
{ } }

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

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

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

 package p04.GenerateTypeDemo.Demo06.GenerateUpperLimitDemo02;

 import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator; class Person
{
private String name;
private int age; public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }
class Student extends Person
{ public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} }
public class GenerateUpperLimitDemo {
public static void main(String args[])
{
ArrayList <Person>al=new ArrayList<Person>();
al.add(new Person("zhangsan",23));
al.add(new Person("lisi",24));
print(al); ArrayList<Student>al1=new ArrayList<Student>();
al1.add(new Student("wangwu",25));
al1.add(new Student("zhaoliu",26));
print(al1);
} private static void print(Collection<? extends Person> al)
{
for(Iterator<? extends Person>it=al.iterator();it.hasNext();)
{
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
} }

其中,这段代码是重点:

 private static void print(Collection<? extends Person> al)
{
for(Iterator<? extends Person>it=al.iterator();it.hasNext();)
{
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}

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

使用上限有什么好处?

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

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

3.泛型的下限。

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

举例:

 package p04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;

 import java.util.Comparator;
import java.util.TreeSet; class Person implements Comparable<Person>
{
private String name;
private int age; @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
}
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
class Student extends Person
{ public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} }
public class GnerateDownLimitDemo {
public static void main(String args[])
{
//Demo1();
Demo2();
} /*
* 该方法演示传入父类比较器仍然能够正常添加元素
*/
private static void Demo2() {
TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByAny());
ts.add(new Student("zhangsan",23));
ts.add(new Student("lisi",24));
System.out.println(ts); TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByAny());
tst.add(new Worker("zhaoliu",26));
tst.add(new Worker("wangwu",25));
System.out.println(tst); } private static void Demo1() {
TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByStudent());
ts.add(new Student("zhangsan",23));
ts.add(new Student("lisi",24));
System.out.println(ts); TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByWorker());
tst.add(new Worker("zhaoliu",26));
tst.add(new Worker("wangwu",25));
System.out.println(tst);
}
}
class ComparatorByStudent implements Comparator<Student>
{ @Override
public int compare(Student o1, Student o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
} }
class ComparatorByWorker implements Comparator<Worker>
{
@Override
public int compare(Worker o1, Worker o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
class ComparatorByAny implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
} }

4.泛型上限的体现。

Collection类的addAll方法:

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

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

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

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

5.泛型下限的体现。

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

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

实例:

 package p04.GenerateTypeDemo.Demo07.GenerateDownLimitDemo01;

 import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet; class Person implements Comparable<Person>
{
private String name;
private int age; @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
}
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
class Student extends Person
{ public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} }
public class GnerateDownLimitDemo {
public static void main(String args[])
{
//Demo1();
Demo2();
}
/*
* 该方法演示传入
*/
private static void Demo2() {
TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByAny());
ts.add(new Student("zhangsan",23));
ts.add(new Student("lisi",24));
System.out.println(ts); TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByAny());
tst.add(new Worker("zhaoliu",26));
tst.add(new Worker("wangwu",25));
System.out.println(tst); } private static void Demo1() {
TreeSet <Student>ts=new TreeSet<Student>(new ComparatorByStudent());
ts.add(new Student("zhangsan",23));
ts.add(new Student("lisi",24));
System.out.println(ts); TreeSet<Worker>tst=new TreeSet<Worker>(new ComparatorByWorker());
tst.add(new Worker("zhaoliu",26));
tst.add(new Worker("wangwu",25));
System.out.println(tst);
}
}
class ComparatorByStudent implements Comparator<Student>
{ @Override
public int compare(Student o1, Student o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
} }
class ComparatorByWorker implements Comparator<Worker>
{
@Override
public int compare(Worker o1, Worker o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
class ComparatorByAny implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
} }

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

最新文章

  1. 学习ROS的基本知识,节点、话题、服务等
  2. lucene-查询query-&gt;TermQuery按词条搜索
  3. Nginx+HTTPS(SSL/TLS)
  4. Windows Server R2服务器 IIS7 部署MVC3网站
  5. linux命令打开程序
  6. 大型情感类电视连续剧--Android高德之旅(3)地图交互
  7. C# Windows服务安装出现System.Security.SecurityException异常解决办法
  8. cocos2d-x环境的搭建之xcode-本人亲历成功搭建!
  9. Android动态布局,并动态为TextView控件设置drawableLeft、drawableRight等属性加入图标
  10. win10系统 L2TP连接尝试失败:ERROR因为安全层在初始化与远程计算机的协商时遇到了一个处理错误
  11. Linux 查看进程
  12. 团队作业9——展示博客(Beta版本)
  13. firewall配置
  14. Linux编程 10 (shell外部命令与内建命令,alias ,type命令)
  15. python函数基础用法
  16. NSCTF2015 逆向第五题分析
  17. hihocoder217周 树形DP
  18. golang应用打包成docker镜像
  19. 用谷歌浏览器Chrome浏览jQuery Mobile页面需要配置Tomcat服务器
  20. DDD模式

热门文章

  1. jenkins Auth fail验证失败
  2. IDEA 编译找不到符号,文件却没有错误。
  3. 【MavenWeb】初探:创建一个Maven Web项目
  4. 求最大公约数和小于n的所有质数
  5. LIGHTSWITCH 连接 MYSQL,中文字符不能保存----解决方法。
  6. ubuntu14.04和win7共享文件夹
  7. Qt 程序运行图标
  8. FastReport报表对象介绍一:“Text”对象
  9. Python: 程序print到文件中
  10. 【leetcode】Binary Tree Zigzag Level Order Traversal (middle)