jdk 1.5新特性——泛型

来源:互联网 发布:overture mac 编辑:程序博客网 时间:2024/05/16 17:55
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

15,泛型

15.1泛型

泛型的符号:<泛型标识符,泛型标识符……>

泛型的作用:泛型就是用于接收具体引用数据类型的参数范围。

泛型什么时候用?

当操作的引用数据类型不确定的时候,就可以使用泛型。

使用泛型的好处:

1,将运行时期的问题转到的编译时期。

2,避免了强转的麻烦。

泛型是JDK1.5的新特性,目的是增加安全性。

15.2泛型的擦除和补偿

java源文件中定义的泛型在运行时会被擦除,生成的字节码文件是不带泛型的,称为泛型的擦除。

当在运行.class字节码文件时,会进行泛型的补偿,目的是避免使用者强转的动作。

泛型在集合、类、方法和接口中都有广泛的应用。

15.3泛型类

当类中操作的引用数据类型不确定时,就可以使用泛型类

类上定义泛型的格式:

权限饰符 class类名<泛型标识符1,泛型标识符2…….>{

                    …….CODE;

}

如:集合框架中的ArrayList<E>,定义了泛型,用来明确集合中要存放什么类型的元素,集合对象创建时需要传入具体的引用数据类型,一旦集合的泛型接收了具体的引用数据类型,那么这个集合中只能存储这一类型的元素,当传入其它类型的元素,编译器就会报错。

   ArrayList<String>al=new ArrayList<String>();      //添加元素      al.add("abc1");      al.add("abc2");      al.add("abc2");      al.add("abc1");      al.add("abc4");      al.add("abc5");for(Iterator<String> it=al.iterator();it.hasNext();){      String s=it.next();//如果不加泛型就需要强转:String s=(String)it.next();      System.out.println(s);      }


 

如上,集合泛型为String类型,那么集合中的元素,就必须是这一类型,否则编译会报错,提高了安全性。

在元素的取出过程中,因为next()取出的元素类型默认是Object类型,如果加了泛型就不需要再进行强转的动作,否则必须要强转,避免了强转的麻烦。

如:以下自定义类中使用的泛型。

public class GenericDemo{   public static void main(String[]args){   Person<String,Integer> person=new Person<String,Integer>("lisi",23);//创建对象时指定具体泛型类型。   Student<String,Integer> student=new student<String,Integer>("zhangsan",23,100);      person.show();      student.show();       }}class Person<N,A>{//Person类上定义了泛型   private Aa;   private Nn;   Person(){         }     Person(N n,A a){//构造参数使用了类上的泛型      this.n=n;      this.a=a;   }     public void show(){      System.out.println("姓名:"+this.n+" 年龄:"+this.a);   }}class Student<N,A>extends Person<N,A>{//当子类继承父类时,没有传入具体泛型类型时,子类也要定义泛型    private A a;   private N n;   private int s;   Student(N n, A a, int s) {      this.n=n;      this.a=a;      this.s = s;   }   public void show(){      System.out.println("姓名:"+this.n+"年龄:"+this.a+"分数:"+this.s);   }  }/* 姓名:lisi 年龄:23姓名:zhangsan年龄:23分数:100 */

15.4泛型方法

如果一个类定义了泛型,那么类中的方法可以使用类上的泛型作为参数。当然,如果方法中的参数类型不确定,则可以在方法上重新定义泛型。

注意:泛型在方法上的位置,只能定义在返回值的前面,修饰符的后面

格式:

权限修饰符 成员修饰符 <泛型标识符1,泛型标识符2……>返回值类型 方法名称(泛型标识符1 变量,泛型标识符2 变量,.....,其它参数{ 

            方法体;  

    }

如:

class Generic<T>{//定义了泛型的类   private T  t;   Generic(T t){      this.t=t;   }   public void show_1(T t){//此方法的参数直接使用了类上的泛型,类上传入什么类型,这个方法的参数就是什么类型。   }   public <A> void show_2(A a){//此方法的参数,没有使用类上的泛型,而是使用了其他的泛型,则需要在方法上定义泛型。   }   public static <B> void show_3(B b){//注意,对于静态方法的参数是不能直接访问类上的泛型的,如果要使用泛型则需要在方法上重新定义泛型。  }}

注意:对于静态方法是不能直接访问类上的泛型的,因为类上的泛型是依赖对象的,而静态方法不需要对象去调用,所以,静态方法不能直接使用类上定义的泛型。如果静态方法要使用泛型,则需要在静态方法上定义泛型。

 

15.5泛型接口 

格式:

interface接口名<泛型标识符1,泛型标识符2……>{

}

如:

interface Inter<T>{   void show(T t);}


 

注意:如果一个类实现了带有泛型的接口时,如果没有明确具体泛型类型,则这个类也必须要定义泛型。

如:

interface Inter<T>{   void show(T t);}class Generic <T> implements Inter<T>{//没有明确接口上泛型的具体类型,类也要定义泛型    @Override   public void show(T t) {  }  }如果在实现一个泛型接口时,明确具体的泛型类型,就把具体的类型传给接口上的泛型。这样类上就需要再定义泛型。

如:

interface Inter<T>{   void show(T t);}class Genericimplements Inter<String>{//明确接口上泛型的具体类型,直接传入具体类型到接口上的泛型。    @Override   publicvoid show(String t) {  }  } 

15.6泛型通配符

泛型通配符:?表示未知的泛型类型。

用字母作为泛型标识符和泛型通配符?有什么区别呢?

用字母作为泛型的标识符,可以对其进行操作。

如:泛型方中,作为方法的返回值 ,作为一个类型,声明一个变量,传给类中的构造函数等等。

public <T> T show(T t){

//方法体;
}

 

而泛型通配符,代表未知的任意类型,是不能够直接操作的,通配符多用于对泛型的限定。

泛型的限定分为:上限和下限

上限:<? extends具体引用类型A> ,表示可以接收A类型及其A的子类类型。

下限:<? super具体引用类型B>,表示可以收的B类型及B的父类类型。

上限和下限同样可以用于对字母泛型标识符的限定。

 

如:上限

public class GenericDemo{   public static void main(String[]args){      new Generic().show("abc"); //传入字符串类型,可以打印      new Generic().show(123);//传入其它类型,就报错。   }}class Generic{   public <T extends String> void show(T t){//show(T t)方法的参数类型T必须是,String及其子类,不能传入其它类型参数。      System.out.println(t);   }}


 

如:下限

public class GenericDemo<T>{   public static void main(String[]args){      Person<String> p=new Person<String>("LISI",23);      new Generic().show(p);   }  }class Generic{   public void show(Person<?super String> g){//此方法,用来接收Person类型 参数,对Person的泛型进行了下限。      System.out.println(g.getT()+":"+g.getAge());   }  }class Person<T>{   private T t;   private int age;   public Person(T t,int age) {      super();      this.t = t;      this.age = age;   }      public T getT() {      return t;   }    public int getAge() {     return age;   }}

15.7泛型在集合中的应用

泛型在集合中都有所应用,集合中使用泛型可以避免强转。集合定义泛型,在创建集合对象时,可以明确具体的泛型类型,元素在取出时,就不需再进行强转。

如:ArrayList集合

public class GenericDemo<T>{   public static void main(String[]args){      ArrayList al=newArrayList();//创建集合对象      al.add("abc1");//add(Objectobj);方法中接收的参数都会被提升为Object类型。      al.add("abc2");      al.add("abc3");      al.add("abc4");            Iterator it=al.iterator();      while(it.hasNext()){         String s=(String)it.next();//添加的元素被提升为Object类型,取出时也是Object类型,要强转。         System.out.println(s);      }   }  }

因为没有加泛型,所以在元素取出时必须要强转。

把泛型加入集合:

:import java.util.ArrayList;import java.util.Iterator; public class GenericDemo<T>{   public static void main(String[]args){      ArrayList<String> al=new ArrayList<String>();//创建集合对象,并明确泛型类型      al.add("abc1");//add(Objectobj);方法中接收的参数都会被提升为Object类型。      al.add("abc2");      al.add("abc3");      al.add("abc4");            Iterator <String>it=al.iterator();//元素的取出明确泛型      while(it.hasNext()){         String s=it.next();//添加的元素被是String,取出时也是String类型,不需要强转。         System.out.println(s);      }   }  }


 

可见,泛型的应用,不仅可以对集合中元素的添加进行类型的限定,增强安全性,避免出错,而且避免了元素在取出中强转的麻烦。

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------