Java泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节。(《Java编程思想--第15章》)
一、简单泛型
1.Holder1只接受int类型的参数
public class Holder1{
private int a;
public class Holder(int a){this.a = a ;}
public Holder1 get(){return a;}
public void set(int a){this.a = a;}
}
2.Holder2接收Object类型的参数,可以接收Object类型和所有继承自Object类型的参数
public class Holder2{
private Object a;
public Holder2(Object a){this.a=a;}
public Holder2 get(){return a;}
public void set(Object a){this.a=a;}
public static void main(String[] args){
Holder2 h2=new Holder2(1);
Integer i=(Integer)h2.get();
h2.set(new String("abc"));
String s = (String)h2.get();
}
}
3.Holder3先不指定类型,而是稍后再决定具体使用什么类型
public class Holder3<T>{
private T a;
public Holder3(T a){this.a=a;}
public T get(){return a;}
public void set(T a){this.a=a;}
public static void main(String[] args){
Holder3 h3 = new Holder3(new String("abc"));
//h3.set(1);//会报错
}
}
原则:无论何时,只要能做到,就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么久应该只使用泛型方法。
二、泛型方法
对一个static的方法,无法访问泛型类的类型参数。所以,要定义泛型化方法,需要将泛型参数列表置于返回值之前。
但是这个output方法,并不是一个static类型的。
下图,参数列表由T,K组成
三、extends和super的含义
先声明三个类Human Father Son
//Human.java
public class Human{}
//Man.java
public class Man extends Human{}
//Father.java
public class Father extends Man{
int a;
static int count=0;
public Father(int a){
this.a=a;
count++;
}
}
1.<? extends Man>上界,先写段代码感受一下
!!! 跟猜想的完全不一样有木有? extends Father并不接受 Father的子类,甚至不接受Object类型,只接受null。
原因分析:? extends Father代表的是Father和继承自Father的类型,但是编译器并不知道具体会放入什么类型的变量,所以就都不接收。只有null可以代表所有类型,所以可以被接受。
2.<? super Man>下界,再写段代码,感受一下
依然跟猜想的不太一样, <? super Man>的意思并不是接受Man的基类,而是接受Man和Man的子类类型。
总结起来就是,编译器可以自动完成向上转型,但无法自动向下转型。比如这个list2,Father一定是Man,而Human不一定是Man类型。
3.现在知道了super和extends的区别,来研究一下extends的用法。
extends不能用于add,但是可以用于get,先准备好三个方法备用:
public static ArrayList<Human> getHumanList(){//获取一个Human类型的list
ArrayList<Human> humans = new ArrayList<>();
humans.add(new Man());
humans.add(new Man());
humans.add(new Father(1));
return humans;
}
public static ArrayList<Man> getMenList(){//获取一个Men类型的list
ArrayList<Man> men = new ArrayList<>();
men.add(new Man());
men.add(new Man());
men.add(new Father(1));
return men;
}
public static ArrayList<Father> getFatherList(){//获取一个Father类型
ArrayList<Father> fathers = new ArrayList<>();
// fathers.add(new Man());
// fathers.add(new Man());
fathers.add(new Father(1));
return fathers;
}
可能有人和我有一样的疑问,list没法add,那get什么呢?这就用到了上面的三个方法
可以直接把一个Man类型的队列赋值给list1.
① list1 = getMenList()不报错
②list1 = getFatherList()没问题(编译器可以向上转型,把Father向上转型为Man,转型后变量a的值未丢失)
③list1 = getHumanList()会报错,还是一样的原因,Human类型的数组无法保证是Man类型的。
4.super的用法
get到的只能是Object类型,向下转型需要强转,因为编译器不知道get到的是一个什么类型的变量。
不过有个地方我没太懂。这个地方get到的类型,为什么不能用Man接着就好了?(因为添加的都是Man和Man的子类类型啊)为什么一定要用Object呢?