zoukankan      html  css  js  c++  java
  • java泛型(擦除)

    java泛型是用擦除实现的,即在编译时把类型信息变为object,然后运行是再动态确定类型信息。

     1 //简单的泛型
     2  class Test<T>
     3  {
     4    private T e;
     5    public void set(T e){
     6      this.e = e;
     7    }
     8    public void print(){
     9       System.out.println(e);
    10    }
    11  }

    反编译后:

     1 class Test
     2  {
     3  
     4      Test()
     5      {
     6      }
     7  
     8      public void set(Object obj)
     9      {
    10          e = obj;
    11      }
    12  
    13      public void print()
    14      {
    15          System.out.println(e);
    16      }
    17  
    18      private Object e;
    19  }

    可见,编译器只是简单把类型信息T变为了Object,利用这一点我们可用反射机制突破编译器的限制

     1 class Main 
     2  {
     3      
     4      @SuppressWarnings("unchecked")
     5      public static void main(String[] args) throws Exception
     6      {
     7        //这里把类型参数设为String
     8        Test<String> t = new Test<String>();
     9        //通过反射把Integer对象赋给成员变量e
    10        t.getClass().getMethod("set",Object.class).invoke(t,new Integer(1));
    11        t.print();
    12      }
    13  }
    14  
    15  class Test<T>
    16  {
    17    private T e;
    18    public void set(T e){
    19      this.e = e;
    20    }
    21    public void print(){
    22       System.out.println(e);
    23    }
    24  }

    运行结果:1

    Java中的泛型做了什么

    首先看一下Java中的泛型做了什么。看下面这段代码:

    public class GenTest<T> {
        T value;

        
    public T getValue() {
            
    return value;
        }

        
    public void setValue(T t) {
            value 
    = t;
        }
    }


    使用javap命令反编译生成的GenTest类的class文件,可以得到下面的输出:

    javap --p GenTest
    Compiled from 
    "GenTest.java"
    public class GenTest extends java.lang.Object{
    java.lang.Object value;

    public GenTest();
      Code:
       
    0:   aload_0
       
    1:   invokespecial   #12//Method java/lang/Object."<init>":()V
       4:   return

    public java.lang.Object getValue();
      Code:
       
    0:   aload_0
       
    1:   getfield        #23//Field value:Ljava/lang/Object;
       4:   areturn

    public void setValue(java.lang.Object);
      Code:
       
    0:   aload_0
       
    1:   aload_1
       
    2:   putfield        #23//Field value:Ljava/lang/Object;
       5:   return

    }


    我们清楚的看到,泛型T在GenTest类中就是Object类型(java.lang.Object value;)。同样,get方法和set方法也都是将泛型T当作Object来处理的。如果我们规定泛型是Numeric类或者其子类,那么在这里泛型T就是被当作Numeric类来处理的。

    好,既然GenTest类中没有什么乾坤,那么我们继续看使用GenTest的时候又什么新东西:

    public class UseGenTest {

        
    public static void main(String[] args) {
            String value 
    = "value";
            GenTest
    <String> test = new GenTest<String>();
            test.setValue(value);
            String nv 
    = test.getValue();
        }
    }


    使用javap命令反编译生成的GenTest类的class文件,可以得到下面的输出:

    D:\mymise\eclipse\workspace\Test\bin>javap --p UseGenTest
    Compiled from 
    "UseGenTest.java"
    public class UseGenTest extends java.lang.Object{
    public UseGenTest();
      Code:
       
    0:   aload_0
       
    1:   invokespecial   #8//Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       
    0:   ldc     #16//String value
       2:   astore_1
       
    3:   new     #18//class GenTest
       6:   dup
       
    7:   invokespecial   #20//Method GenTest."<init>":()V
       10:  astore_2
       
    11:  aload_2
       
    12:  aload_1
       
    13:  invokevirtual   #21//Method GenTest.setValue:(Ljava/lang/Object;)V
       16:  aload_2
       
    17:  invokevirtual   #25//Method GenTest.getValue:()Ljava/lang/Object;
       20:  checkcast       #29//class java/lang/String
       23:  astore_3
       
    24:  return

    }


    重点在17、20和23三处。17就是调用getValue方法。而20则是关键——类型检查。也就是说,在调用getValue方法之后,并没有直接把返回值赋值给nv,而是先检查了返回值是否是String类型,换句话说,“String nv = test.getValue();”被编译器变成了“String nv = (String)test.getValue();”。最后,如果检查无误,在23处才会赋值。也就是说,如果没有完成类型检查,则会报出类似ClassCastException,而代码将不会继续向下执行,这就有效的避免了错误的出现。
    也就是说:在类的内部,泛型类型就是被基类型代替的(默认是Object类型),而对外,所有返回值类型为泛型类型的方法,在真正使用返回值之前,都是会经过类型转换的。

    努力奋斗的小墨鱼 ---- http://www.cnblogs.com/WayneZeng/
  • 相关阅读:
    老罗锤子手机发布会,我感到深深地愧疚!
    微价值:专访《甜心爱消除》的个人开发者Lee,日入千元
    [个人开发者赚钱二]从自己最熟悉的方面入手,获取小利
    [个人开发者赚钱一]改变思维,从心开始
    个人开发者赚钱一、改变思维,从心开始
    OC中的点语法,成员变量的作用域
    OC self super isa指针
    OC面向对象多态笔记
    OC面向对象继承关系和组合关系笔记
    OC面向对象封装
  • 原文地址:https://www.cnblogs.com/WayneZeng/p/2697233.html
Copyright © 2011-2022 走看看