泛型,把类型参数化。
泛型的命名规则:
不要小写字母表示泛型名字,虽然这也没什么错。如果可以的话,泛型就用“T”来表示。
还有就是类上的泛型和方法上的泛型,名字尽量不要相同。
它在JDK1.5之后出现,主要的作用是解决安全问题
比如下面的安全问题:
private static void method_1() {
ArrayList al=new ArrayList();
al.add("abc01");
al.add("abc0991");
al.add("abc014");
al.add(4);
Iterator it=al.iterator();
while(it.hasNext()){
String next=(String)it.next();
System.out.println(next);
}
}
ArrayList可以添加任何类型的元素,该方法在程序编译时并不会出现问题。但是在迭代取值时,Integer类型的值无法转换为String,会出现ClassCastException异常。
而避免这种问题的,就是指定ArrayList的元素的类型,把类型参数化。比如这样:
ArrayList<String> al=new ArrayList<String>();
al.add("abc01");
al.add("abc0991");
al.add("abc014");
//al.add(4); 编译时提示错误
本例子中,泛型可以把一些错误提前到了编译时期,方便了调试。而且在迭代时,不再需要强制转化。
Iterator<String> it=al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
1,泛型定义在类上
ArrayList类上的泛型
public class ArrayList<E> extends AbstractList<E>
ArrayList al=new ArrayList();
传递进去的类的泛型是String,而定义在类上的泛型,在整个类中都是有效的。
类上的泛型可以由一个也可以由多个:
class GenericForClass1<T>{
private T temp;
private void set(T t){
this.temp=t;
}
private T get(){
return temp;
}
private void print(){
System.out.println(temp);
}
}
private void generic_1() {
GenericForClass1<Integer> generic=
new GenericForClass1<Integer>();
generic.set(1);
generic.print();
}
class GenericForClass2<T1,T2>{
private T1 t1;
private T2 t2;
private void setT1(T1 t){
this.t1=t;
}
private T1 getT1(){
return t1;
}
private void setT2(T2 t){
this.t2=t;
}
private T2 getT2(){
return t2;
}
private void print(){
System.out.println(t1+"----"+t2);
}
}
private void generic_1() {
GenericForClass2<Integer,String> generic=
new GenericForClass2<Integer,String>();
generic.setT1(1);
generic.setT2("ronaldo");
generic.print();
}
2,泛型定义在方法上
class GenericForClass1<T>{
private T temp;
private void set(T t){
this.temp=t;
}
private T get(){
return temp;
}
private void print(){
System.out.println(temp);
}
}
泛型定义在类上后,操作的类型就固定了。比如下面的写法就有问题:
GenericForClass1<Integer> generic=
new GenericForClass1<Integer>();
eneric.set("1");//编译出错
为了让不同的方法操作不同的类型,我们可以不把泛型定义在类上,而是定义在方法上。
注意的是泛型如果定义在方法上,只对该方法是有效的。
如下:
class GenericForClass1{
private <T>void show(T t){
System.out.println(t);
}
}
private void generic_1() {
GenericForClass1 generic=
new GenericForClass1();
generic.show("1");
generic.show(1);
}
当然也可以在类上定义泛型,而在方法上也定义泛型来操作不同类型。如:
class GenericForClass1<T>{
private T t;
private void set(T t){
this.t=t;
}
private T get(){
return t;
}
private void print(){
System.out.println(t);
}
private <S>void show(S s){
System.out.println(s);
}
}
private void generic_1() {
GenericForClass1<Integer> generic=
new GenericForClass1<Integer>();
generic.set(1);
generic.set("1");//编译错误,set方法的泛型和类是绑定的
generic.print();
generic.show("1");
}
静态方法的泛型:
class Demo1<T>{
private void show(T t){
System.out.println(t);
}
private <T>void set(T t){
System.out.println(t);
}
//编译时会出现错误
private static <T> void method(T t){
System.out.println(t);
}
}
静态方法访问类上的泛型,编译出错。原因是,建立对象后才会有泛型。
比如ArrayList al=new ArrayList();
我们知道静态成员是先加载的。
既然静态方法无法访问类上的泛型,我们可以为它在方法上定义泛型。
private static <S> void method(S s){
System.out.println(s);
}
3,泛型定义在接口上
//泛型定义在接口上
interface MyInter<T>{
void access(T t);
}
//实现接口指定泛型
class MyImpl1 implements MyInter<String>{
@Override
public void access(String t) {
}
}
//实现接口后不知道传递什么类型
class MyImpl2<T> implements MyInter<T>{
@Override
public void access(T t) {
}
}