初识Java泛型以及桥接方法(java的泛型及实现原理)

  本篇文章为你整理了初识Java泛型以及桥接方法(java的泛型及实现原理)的详细内容,包含有java泛型接口是什么 java的泛型及实现原理 java 泛型接口 java泛型t 初识Java泛型以及桥接方法,希望能帮助你了解 初识Java泛型以及桥接方法。

  泛型的由来

  在编写程序时,可能会有这样的需求:
容器类,比如java中常见的list等。为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型。
此时可能会有IntList、LongList、StringList、XXXList等多个List容器类,但是容器类内部的各个方法,除了add、remove、get方法操作的数据类型不同意外,几乎全部相同。为了方便起见,可以使用ObjectList,但是在get的数据是Object类型,需要进行强制类型转换,这就会造成一些程序运行时的隐患。

  通过查询网络资料时,发现这个需求对于泛型的需要最迫切。于是在jdk1.5(2004年)中,java加入了泛型。

  什么是泛型

  泛型:参数化类型。将类类型,作为参数,进行传递。
泛型参数,可以为多个,使用尖括号括起来。
比如,通过实例化List容器时,指定容器类类型String,实现了String容器。

  

List String list= new LinkedList String ();

 

  list.add("1");//没有编译错误

  list.add(1);//编译错误

 

  如何实现泛型

  在java中,可实现泛型接口、泛型类、泛型方法。

  1、泛型接口:常见的List接口,Map接口,都是泛型接口。
举例:

  

public interface Test T {

 

   public void add(T element);

   public T get(int index);

  }

 

  2、泛型类:LinkedList、ArrayList、HashMap、TreeMap等都是泛型类,并且他们实现了泛型接口;

  举例:

  

public class Target T, E implements Test T {

 

   private Object[] list=new Object[100];

   private int index=0;

   public void add(T element){

   list[index++]=element;

   public T get(int index){

   return (T)list[index];

  }

 

  3、泛型方法:同泛型接口和泛型类的定义稍微有些不同。

  举例:

  

public T T add( Class T clz){

 

   T instance=clz.newInstance();

   return instance

  }

 

  在定义泛型接口、类、方法时,可以添加多个泛型形参,一般使用大写字母表示,并用逗号分隔,泛型定义处,使用尖括号将所有泛型形参括起来。

  泛型接口、类的泛型形参,放置在接口或类名的后面。
泛型方法的泛型形参,放置在方法返回类型的前面即可。

  注意,java的泛型属于code share,只是在编译时使用,用于检查传递给泛型类、方法的数据类型是否符合泛型定义,泛型类和方法中的泛型会在编译成功后擦出,成为Object类型,编译器并会在泛型数据操作时,自动添加类型转换。由于编译期间保证了泛型类型的正确使用,因此自动添加的类型转换是安全的。
举例:
使用List容器,调用其方法

  

public class Main{

 

   public static void main(String[] args){

   List Long ttt=new LinkedList Long ();

   tt.add(1L);

   Long value=tt.get(0);

  }

 

  在编译后的class文件,可翻译为:

  

public class Main{

 

   public static void main(String[] args){

   List ttt=new LinkedList();

   tt.add(1L);

   Long value=(Long)tt.get(0);

  }

 

  编译时,编译器会检查凡是使用泛型类实例的地方,是不是按照泛型的规定,进行传参的。

  比如ttt.add(1L),编译器会检查传入的参数是不是Long型;还有tt.get(0),编译器会自动加上类型转换。最终看到编译后,泛型类的泛型被擦出了。
类型擦出导致,以下输出会为true,因为泛型类不会因为不同的泛型类型,导致生成不同的类。

  

List String list1=new LinkedList String ();

 

  List Integer list2=new LinkedList Integer ();

  System.out.println(list2.getClass()==list1.getClass());//输出为true

 

  泛型定义时的约束

  定义泛型形参时,可以使用extends限制泛型的范围。
比如使用 T extends K ,表示T必须是类K的子类,或者接口K的实现类。
比如使用 T super K ,表示T必须是类K的父类,或类K实现的接口。
注意:extends并不表示类的继承含义,只是表示泛型的范围关系。
注意:extends中可以指定多个范围,实行泛型类型检查约束时,会以最左边的为准。

  java泛型实现的原理

  在C++中也有泛型的概念,但java的泛型实现原理同C++是不一样的。
泛型实现原理有两种:
1、为使用的泛型类,单独生成一份非泛型的具体类。
比如List String list=new ArrayList String ,在程序编译时,会单独生成一份StringArrayList类,并且类里面所有的操作元素都是String类。
2、采用擦出机制,泛型接口或类中,所有使用泛型形参的地方,全部擦除,替换为Object类型(java中所有类的父类)。所有相同泛型类的实例共享使用泛型类的代码。在泛型类的实例进行数据操作的地方(泛型类外部,自定义的程序部分),由编译器检查操作的参数是否为泛型类实例定义时的类类型,必要时自动添加强制类型转换。

  在擦除时,如果 T extends XXClass ,T擦出后会变为XXClass。
如果 T extends AClass,BClass ,T擦出后,类型为AClass,以最左边的类型为最终类型,这点要注意。

  首先举一个例子。

  

public class A T {

 

   public T get(T a){

   //a进行一些操作

   return a;

  public class B extends A String {

   @override

   public String get(String a){

   //a进行一些操作

   return a;

  }

 

  由于类型擦出机制的存在,按理说编译后的文件在翻译为java应如下所示

  

public class A{

 

   public Object get(Object a){

   //a进行一些操作

   return a;

  public class B extends A{

   @override

   public String get(String a){

   //a进行一些操作

   return a;

  }

 

  @override意味着B对父类A中的get方法进行了重写,但是依上面的程序来看,只是重载,依然可以执行父类的方法,这和期望是不附的,也不符合java继承、多态的特性。

  注:子类重写父类方法,只要此实例的实际类型是子类类型了(不是引用类型),便不能调用父类的方法,这是语言的多态特性。

  为了解决这个问题,java在编译期间加入了桥接方法。编译后再翻译为java原文件,应如下所示:

  

public class A{

 

   public Object get(Object a){

   //a进行一些操作

   return a;

  public class B extends A{

   @override

   public String get(String a){

   //a进行一些操作

   return a;

   public Object get(Object a){

   return get((String)a)

  }

 

  类B中的第二个方法,即为桥接方法。桥接方法重写了父类相同的方法,并且桥接方法中,最终调用了期望的重写方法,并且桥接方法在调用目的方法时,参数被强制转换为指定的泛型类型。

  桥接方法测试:

  

A a=new B();

 

  a.get(new Object());

 

  由于A未声明泛型类型,编译期间会警告存在类型转换错误。

  运行期间,还真抛出了类型转换错误,Object to String。

  实例a实际类型为B,在调用a.get方法时最终调用了B类中的桥接方法,保证了传入参数为子类继承父类使用的泛型类型。

  以上就是初识Java泛型以及桥接方法(java的泛型及实现原理)的详细内容,想要了解更多 初识Java泛型以及桥接方法的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: