【JAVA之泛型】
一、引例。
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类型的,所以可以传入各种类型的参数,所以实际参数类型不确定,所以使用?。
【JAVA之泛型】的更多相关文章
- [改善Java代码]Java的泛型是类型擦除的
泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...
- Java 中泛型的全面解析(转)
Java泛型(generics) 是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在J ...
- Java中泛型 类型擦除
转自:Java中泛型是类型擦除的 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类 ...
- Java 泛型 Java使用泛型的意义
Java 泛型 Java使用泛型的意义 @author ixenos 直接意义 在编译时保证类型安全 根本意义 a) 类型安全问题源自可复用性代码的设计,泛型保证了类型安全的复用模板 b) 使用复用性 ...
- 跟着刚哥梳理java知识点——泛型(十三)
一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: public class GenericTest { public static void main(String[] a ...
- 【Java】泛型学习笔记
参考书籍 <Java核心技术:卷1> 泛型, 先睹为快 先通过一个简单的例子说明下Java中泛型的用法: 泛型的基本形式类似于模板, 通过一个类型参数T, 你可以"私人定制&qu ...
- [转] Java 的泛型擦除和运行时泛型信息获取
原文链接 https://my.oschina.net/lifany/blog/875769 前言 现在很多程序员都会在简历中写上精通 Java.但究竟怎样才算是精通 Java 呢?我觉得不仅要熟练掌 ...
- Java 容器 & 泛型:五、HashMap 和 TreeMap的自白
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...
- 【译】9. Java反射——泛型
原文地址:http://tutorials.jenkov.com/java-reflection/generics.html ===================================== ...
- Java“禁止”泛型数组
Java“禁止”泛型数组 原文:https://blog.csdn.net/yi_Afly/article/details/52058708 1. 泛型定义泛型编程是一种通过参数化的方式将数据处理与数 ...
随机推荐
- (集成电路卡)ID卡
IC卡(intergrated Circuit Card,集成电路卡),又称为智能卡,智慧卡,微电路卡,微芯片卡 等等. 它是将一个微电子芯片嵌入符合ISO 7816标准的卡基中,做成卡片形状. IC ...
- am335x UART1输入u-boot 调试信息代码修改
AM335x 调试信息UART1输出代码修改1. 关于pin_mux 的配置代码修改位置:/board/forlinx/ok335x/mux.c void enable_uart0_pin_mux( ...
- 转:linux下bwa和samtools的安装与使用
bwa的安装流程安装本软体总共需要完成以下两个软体的安装工作:1) BWA2) Samtools1.BWA的安装a.下载BWA (download from BWA Source Forge ) ht ...
- linux 编程环境搭建过程记录
1, 安装centos 7 最小版 过程略 ...... 2, 安装桌面安装yum groupinstall "GNOME Desktop" 更新系统运行级别ln -sf /li ...
- 5.3(2)----机器人走方格2(CC150)
这道题只需要把障碍点都设为0就可以了. public static int countWays(int[][] map,int x, int y){ if( x < 0 || y < 0) ...
- Eclipse不给提示no default proposals
解决方法: (1),找到工程所在的workspace,删除.metadata配置文件. (2),启动eclipse,重新定位到先前的workspace目录置,重建同名工程(不要删除原来的工程,只要建立 ...
- PHP使用curl替代file_get_contents
初学php的朋友们,很容易翻一个错误,在写采集程序或者调用api接口总会有线考虑到使用file_get_contents函数来或许内容,程序的访问量不大倒是没什么影响,但是访问量提升了那非常的悲剧了, ...
- js apply 和 call
http://www.cnblogs.com/KeenLeung/archive/2012/11/19/2778229.html
- ASP.NET页面传值不使用QueryString
ASP.NET页面传值不使用QueryString Asp.net中的页面传值方法: 1 Url传值 特点:主要优点是实现起来非常简单,然而它的缺点是传递的值是会显示在浏览器的地址 ...
- 使用logrotate管理nginx日志文件
本文转载自:http://linux008.blog.51cto.com/2837805/555829 描述:linux日志文件如果不定期清理,会填满整个磁盘.这样会很危险,因此日志管理是系统管理员日 ...