一、泛型接口
interface Inter<T>{
public void show(T t);
}
class InterImple implements Inter<String>{//知道是字符串类型
public void show(String str){
System.out.println("show "+str);
}
}
class InterImple_2<Q> implements Inter<Q>{//不知道是什么类型,使用的时候才知道
public void show(Q q){
System.out.println("InterImple_2.show()+"+q);
}
}
public class Main
{
public static void main(String[] args) {
InterImple in = new InterImple();
in.show("sf");
InterImple_2<Integer> in2 = new InterImple_2<Integer>();
in2.show(2);
}
}
同上,在使用继承时,如果父类的泛型指定了,那么子类就可以不写泛型,如果不指定还是T,那么子类也必须指定为T
泛型与继承关系
若A是B的子类,在多态上,可以将B 向上转型为A,但是在List<A> 与 List<B> ,List<B>就不能赋给List<A>
List<Object> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
l1 = l2; 错误
此处,List<>中无论是什么泛型,两个List都是并列关系,不存在父子关系,如果需要进行如父子关系的赋值等操作,需要使用通配符
二、泛型限定
泛型的通配符,通俗的说就是不管什么类型,都用一个符号表示T,E,X,?...
其中通配符?和通配符T区别不大
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Main
{
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("ads");
al.add("sfdf");
show(al);
ArrayList<Integer> a3 = new ArrayList<Integer>();
a3.add(5);
a3.add(6);
show(a3);
HashSet<Integer> al2 = new HashSet<Integer>();
al2.add(1);
al2.add(2);
show(al2);
}
//如果单纯是打印,通配符用?即可,不能使用 增强for
public static void show(Collection<?> al) //此处的a1 a2 a3 就都可以 付给 al,言外之意就是 <span style="font-family: Arial, Helvetica, sans-serif;">Collection<?> al,是他们的父类,是任何泛型的父类</span>
<span style="white-space:pre"> </span>//<span style="white-space:pre"> </span>而使用 <span style="font-family: Arial, Helvetica, sans-serif;">Collection<Object> al,就不可以,只能放 List<Object></span>
{
Iterator<?> it = al.iterator();
Iterator<?> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
//如果需要返回继续操作
// public static <T> T show(Collection<T> al) {
// Iterator<T> iterator = al.iterator();
// T t = iterator.next();
// return t;
// }
}
PS:不能向声明为通配符的对象中,写入数据
关于迭代器
/*Iterator<T> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}*/
//java5.0 以后用了更为优雅的for each循环,与iterator表示同样的循环
for(T x : al){
System.out.println(x);
}
简洁明了
通配符第一种演示:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Main
{
public static void main(String[] args) {
ArrayList<Worker> al = new ArrayList<Worker>();
al.add(new Worker("abc",12));
al.add(new Worker("dgh",11));
show(al);
ArrayList<Student> a3 = new ArrayList<Student>();
a3.add(new Student("ASD",156));
a3.add(new Student("AFDFD",16));
show(a3);
}
//如果只想打印Man的子类
//Collection<Man>不对,Collection<Man> = new ArrayList<Student>();左右类型不匹配
//所以在泛型声明,就可以采用继承的方式
public static void show(Collection<? extends Man> al)
{//
Iterator<? extends Man> it = al.iterator();
while(it.hasNext()){
Man man = it.next();
System.out.println(man);
}
}//等价于
public static <T extends Man> void show1(Collection<T> al)
{//
for(T xT : al)
System.out.println(xT);
}
}
所以泛型存的限定有两种:
上限:?extends E,?只能就收E类型或E的子类
下限:? super E,接受E类型或E的父类
三、上限的体现:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Main
{
public static void main(String[] args) {
ArrayList<Man> al1 = new ArrayList<Man>();
al1.add(new Man("ABC",12));
al1.add(new Man("DGH",11));
ArrayList<Worker> al2 = new ArrayList<Worker>();
al2.add(new Worker("abc",12));
al2.add(new Worker("dgh",11));
ArrayList<Student> al3 = new ArrayList<Student>();
al3.add(new Student("abc",12));
al3.add(new Student("dgh",11));
al1.addAll(al2);//一般存元素的时候,都是上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患
System.out.println(al1.size());
}
}
详细看API文档,addAll方法 : addAll(? extends E),可以存储E及E的所有子类
泛型的使用规则
1.静态方法中不可以使用泛型 解释:static 在实例化之前就存在,但是泛型<T>是在实例化时才确定的
如果要用,必须在静态方法前定义 public static<F> void mthod(F str),必须要先定义,否则报错
2.当一个泛型类是接口或抽象类时,它是不可以创建该泛型类的对象的
3.try-catch不能使用泛型
4.从泛型类派生子类,泛型类型需要具体化
四、下限的体现:
通常对集合中元素进行取出动作时,可以用下限
也就是不论存什么类型(只要是当前父类的子类),都可以用父类型接收
import java.util.Comparator;
import java.util.TreeSet;
import java.util.Iterator;
class ComparaName implements Comparator<Man>{
//按姓名排序
public int compare(Man o1, Man o2) {
// TODO Auto-generated method stub
int t = o1.getName().compareTo(o2.getName());
return t==0?o1.getAge()-o2.getAge():t;
}
}
public class Main
{
public static void main(String[] args) {
TreeSet<Man> al1 = new TreeSet<Man>(new ComparaName());
al1.add(new Man("ABC",12));
al1.add(new Man("DGH",11));
TreeSet<Worker> al2 = new TreeSet<Worker>();
al2.add(new Worker("abc",12));
al2.add(new Worker("dgh",11));
TreeSet<Student> al3 = new TreeSet<Student>(new ComparaName());
al3.add(new Student("abc",12));
al3.add(new Student("dgh",11));
//把学生和工人都加入al1集合
al1.addAll(al3);
al1.addAll(al2);
//都按照Man的排序规则排序
Iterator<Man> it = al1.iterator();
while(it.hasNext())
System.out.println(it.next());
}
}
五、通配符的体现
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class Main
{
public static void main(String[] args) {
ArrayList<Man> al1 = new ArrayList<Man>();
al1.add(new Man("ABC",12));
al1.add(new Man("DGH",11));
ArrayList<Man> al2 = new ArrayList<Man>();
al2.add(new Man("ABC",12));
al2.add(new Man("DGH",11));
boolean flag1 = al1.containsAll(al2);
System.out.println(flag1);
ArrayList<String> al3 = new ArrayList<String>();
al3.add("qwertyi");
al3.add("asd");
boolean flag2 = al1.containsAll(al3);
System.out.println(flag2);
}
//方法 : containsAll(Collection <?> c)
//?不论传什么都接收,就好比Object里的equals方法:"asd".equals(new Worker("asd",12)),编译和运行都是通过的
public static void show(Collection<?> al){
for(Iterator<?> it = al.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
interface Information {
}
class PersonInfor implements Information{
private int age;
private String name;
}
class ContactInfor implements Information{
private String phone;
private String address;
}
class Person<T extends Information>{
//这个person类只能是 Information 或 Information 的子类
public void get(List<? extends PersonInfor> ls){
}
}