个人理解:所谓泛型限定,是指一个方法在接收所传参数引用数据类型时做的限定!
1、<?>:接收指定类型
先看下面的程序
import java.util.*;
public class GenericLimit
{
public static void main(String[] args)
{
ArrayList<String> L1=new ArrayList<String>();
L1.add("001");
L1.add("002");
L1.add("003");
L1.add("004");
L1.add("005");
ArrayList<Integer> L2=new ArrayList<Integer>();
L2.add(001);
L2.add(002);
L2.add(003);
L2.add(004);
L2.add(005);
show(L1);
//show(L2);
}
public static void show(ArrayList<String> L)
{//<指定类型>
ListIterator<String> it=L.listIterator();
while(it.hasNext())
{
System.out.println(it.next().length()+"...");
}
}
}
在show方法里定义了ArrayList<String>泛型后,就不能再通过传入L2来调用show方法,为了解决这个问题,用<?>来解决:根据传进来的类型做决定,类似于Object多态形式。
2、“?”通配符:接收任意类型
代码如下
import java.util.*;
public class GenericLimit
{
public static void main(String[] args)
{
ArrayList<String> L1=new ArrayList<String>();
L1.add("001");
L1.add("002");
L1.add("003");
L1.add("004");
L1.add("005");
ArrayList<Integer> L2=new ArrayList<Integer>();
L2.add(001);
L2.add(002);
L2.add(003);
L2.add(004);
L2.add(005);
show(L1);
show(L2);
}
public static void show(ArrayList<?> L)
{//<?>接收任意类型
ListIterator<?> it=L.listIterator();
while(it.hasNext())
{
System.out.println(it.next()+"...");
}
}
}
结果如下图:
<?>与<T>与<指定类型>的区别:
区别不是很大;但是有区别:
1、<T>代表一个具体类型,传什么类型就是什么类型,<?>是占位符,不明确具体类型,<指定类型>明确规定了传入引用数据类型!
2、静态方法中不能调用类上定义的泛型,因此若用<T>,必须在static后声明<T>;而<?>、<指定类型>不需要在static后声明!
3、由于<?>不明确具体类型,所以相应的不能建立其对象;<T>与<指定类型>均能建立其相应的对象;
4、由于<T>是在接收传入的引用数据类型才明确类型,所以其只能调用Objcet类中的方法,<?>更是如此!但<指定类型>由于一开始就明确了引用数据类型,所以可以调用相应的特有方法!
如<T>代码可以这样写:
public static<T> void show(ArrayList<T> L) //静态方法中不能调用类上定义的泛型,因此若用<T>,必须在static后声明<T>
{
ListIterator<T> it=L.listIterator();
while(it.hasNext())
{
T o=it.next(); //T是传进来的具体类型;但<?>就不能写成? o=it.next();形式!
System.out.println(o+"..."); //由于T是在接收L后才能确定类型,因此只能调用Object类中的方法,不能调用L中特有方法;
} //<span style="font-family: Arial, Helvetica, sans-serif;"><?>更是如此,其只表示占位符的意思,因此等L传递进来,它也不知道传递的什么类型…………</span>
}
<指定类型>
public static void show(ArrayList<String> L) //但若是指定类型的泛型,则不必提前声明了,
{
ListIterator<String> it=L.listIterator();
while(it.hasNext())
{
System.out.println(it.next().length()+"..."); //但由于指定类型固定,所以可以调用L中特有方法
}
}
3、泛型上限:接收本类型和本类型子类
? extends E: 可以接收E类型或者E的子类型。
代码如下:
import java.util.*;
public class Person
{
private String name;
public Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
}
public class Worker extends Person
{
public Worker(String name)
{
super(name); //切记:子类构造方法第一句话必须是super();
}
}
public class Student extends Person
{
public Student(String name)
{
super(name);
}
}
public class GenericLimit
{
public static void main(String[] args)
{
ArrayList<Student> L1=new ArrayList<Student>();
L1.add(new Student("001"));
L1.add(new Student("002"));
L1.add(new Student("003"));
ArrayList<Worker> L2=new ArrayList<Worker>();
L2.add(new Worker("101"));
L2.add(new Worker("102"));
L2.add(new Worker("103"));
show(L1);
show(L2);
}
public static void show(ArrayList<? extends Person> L) //可以接收Person类及Person的子类,即一个方法所能接收传入数据引用数据类型的限定!
{
ListIterator<? extends Person> it=L.listIterator();
while(it.hasNext())
{
System.out.println(( it.next()).getName()+"...");
}
}
}
结果如下:
可见Student类与Worker类均被允许并传递进来!,但是只能调用父类的方法,不能调用子类特有方法!
应用比如:ArrayList中的方法:
即可以接收E即E的子类元素,其中E是在类上定义的泛型。
4、泛型下限:接收本类型和本类型父类
? super E: 可以接收E类型或者E的父类型。
如:
可以传入当前类型父类的比较器,调用父类比较器的方法进行比较!
当多个子类对象的比较方法均和父类方法一致时,将比较器类型定义为父类比较器,通过泛型下限,将父类比较器传入子类对象中,实现比较功能,这样实现了多个子类对象公用一个比较器,而且不允许其体系外的对象使用此比较器!
(1)实现Comparable接口代码:
import java.util.*;
public class Person implements Comparable<Person>//子类将继承父类比较方法
{
private String name;
public Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public int compareTo(Person obj) //父类比较方法
{
Person it=(Person )obj;
return this.name.compareTo(it.name); //按照字符串自然顺序自然排序,
}
}
public class Student extends Person
{
public Student(String name)
{
super(name);
}
public void show()
{
System.out.println("Student");
}
}
public class Worker extends Person
{
public Worker(String name)
{
super(name);
}
}
public class GenericLimit
{
public static void main(String[] args)
{
TreeSet<Student> L1=new TreeSet<Student>();
L1.add(new Student("student--003"));
L1.add(new Student("student--002"));
L1.add(new Student("student--001"));
L1.add(new Student("student--0010"));
TreeSet<Worker> L2=new TreeSet<Worker>();
L2.add(new Worker("worker--101"));
L2.add(new Worker("worker--102"));
L2.add(new Worker("worker--103"));
L2.add(new Worker("worker--1012"));
show(L1);
show(L2);
}
public static void show(TreeSet<? extends Person> L)
{
Iterator<? extends Person> it=L.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName()+"...");
}
}
}
结果如下:
(2)用比较器Comparator建立比较器,传入比较器对象给TreeSet集合,
import java.util.*;
public class NautureComp implements Comparator<Person>
{
public int compare(Person obj1,Person obj2)
{
return (obj2).getName().compareTo((obj1).getName());
}
}
public class Person implements Comparable<Person>//子类将继承父类比较方法
{
private String name;
public Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public int compareTo(Person obj) //父类比较方法
{
Person it=(Person )obj;
return this.name.compareTo(it.name); //按照字符串自然顺序自然排序,
}
}
public class Student extends Person
{
public Student(String name)
{
super(name);
}
public void show()
{
System.out.println("Student");
}
}
public class Worker extends Person
{
public Worker(String name)
{
super(name);
}
}
public class GenericLimit
{
public static void main(String[] args)
{
TreeSet<Student> L1=new TreeSet<Student>(new NautureComp()); //传入的为父类比较器,即 ? super E
L1.add(new Student("student--003"));
L1.add(new Student("student--002"));
L1.add(new Student("student--001"));
L1.add(new Student("student--0010"));
TreeSet<Worker> L2=new TreeSet<Worker>(new NautureComp());
L2.add(new Worker("worker--101"));
L2.add(new Worker("worker--102"));
L2.add(new Worker("worker--103"));
L2.add(new Worker("worker--1012"));
show(L1);
show(L2);
}
public static void show(TreeSet<? extends Person> L)
{
Iterator<? extends Person> it=L.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName()+"...");
}
}
}