`
491823151
  • 浏览: 4510 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

泛型(Generic)

    博客分类:
  • Java
阅读更多

前几天在看撒加老师早期的一些关于泛型的回复,对于泛型深有体会,略作小结。

对于泛型来说,这个JDK1.5加入的新朋友,大家应该都熟悉的再熟悉不过了,在此就不作介绍了,直接进入正题。

(调用撒迦的话来说) ^ ^
Java泛型有这么一种规律:
位于声明一侧的,源码里写了什么到运行时就能看到什么;
位于使用一侧的,源码里写什么到运行时都没了。


下面我来看一下使用侧泛型:

 

import java.util.ArrayList;  
import java.util.List;  
  
public class TestClass {  
    public static void main(String[] args) {  
        List<String> list = new ArrayList<String>(); 
        list.add("dog");
        String s = list.get(0);
    }  
}  

 

 通过jad查看编译后的class文件:

 

public static void main(String args[]){
        ArrayList arraylist = new ArrayList();
        arraylist.add("dog");
        String s = (String)arraylist.get(0);
}

 

我们可以看到编译过后,原先我们定义的泛型信息全部消失了(擦除),并且经过javac编译后自动帮我们添加上了类型转化代码,接下来我们来看下main方法的bytecode:

 

   //    0    0:new             #2   <Class ArrayList>
    //    1    3:dup             
    //    2    4:invokespecial   #3   <Method void ArrayList()>
    //    3    7:astore_1        
    //    4    8:aload_1         
    //    5    9:ldc1            #4   <String "dog">
    //    6   11:invokeinterface #5   <Method boolean List.add(Object)>
    //    7   16:pop             
    //    8   17:aload_1         
    //    9   18:iconst_0        
    //   10   19:invokeinterface #6   <Method Object List.get(int)>
    //   11   24:checkcast       #7   <Class String>
    //   12   27:astore_2        
    //   13   28:return          

 

在第6行的add方法中我们是以一个Object类型添加进容器,在第11行get出来的是Object类型并且通过checkcast (String)来确保我们类型的正确性,并且在这个class文件中没有  Signature:xxxx 的存在(由于1.5以后泛型的加入,class文件格式有所调整,需要将泛型信息记录在class文件中,Signature就是用来记录)。由此可见在使用测的泛型信息全部被擦除掉,并且添加进去的类型是以List<T>决定,这两问题稍后再谈。由此可见在JDK1.4之前我们要手动进行类型检查,在JDK1.5后有了泛型,虽然我们在java源代码中不用手动去进行类型转化,但不代表类型转换就不需要,在编译后的class文件我们看到checkcast的添加,所以可见使用和不使用泛型并不能增加我们什么性能,类型检查都是需要的,我们来看下没有使用泛型的bytecode:

 

  //    0    0:new             #2   <Class ArrayList>
    //    1    3:dup             
    //    2    4:invokespecial   #3   <Method void ArrayList()>
    //    3    7:astore_1        
    //    4    8:aload_1         
    //    5    9:ldc1            #4   <String "dog">
    //    6   11:invokeinterface #5   <Method boolean List.add(Object)>
    //    7   16:pop             
    //    8   17:aload_1         
    //    9   18:iconst_0        
    //   10   19:invokeinterface #6   <Method Object List.get(int)>
    //   11   24:checkcast       #7   <Class String>
    //   12   27:astore_2        
    //   13   28:return          

 

比较下我们可以看到两者没有区别~~

 

接下来我们来看下声明测泛型的使用:

 

什么是声明测泛型?“声明一侧”包括泛型类型(泛型类与泛型接口)声明、带有泛型参数的方法和域的声明。注意局部变量的声明不算在内,那个属于“使用”一侧。(还是撒迦的话) ^   ^

 

接下来我们来看:

import java.util.List;  
import java.util.Map;  
  
public class GenericClass<T> {                
    private List<T> list;                    
   
    private T t;            
      
    public <U> U genericMethod(Map<T, U> m) { 
        return null;  private java.util.List list;  
    }  
}  

 

以上面的两个成员变量list和t为例,通过javap我们查看编译后的class文件,可以看到

 

private java.util.List list;  
Signature: length = 0x2  
   00 07

private java.lang.Object t;  
  Signature: length = 0x2  
   00 0A

 

初看list中不是没有记录我们所定义的泛型信息么?但下面有我们上面提到过的Signature : 00 07(表示的是常量池索引)

到常量池中找出对应的项:

 

const #7 = Asciz       Ljava/util/List<TT;>;;

 

 可以看到泛型信息被我们记录在此,对于成员变量t我们查看其类型信息~

具体泛型在class中的描述形式可以参:http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf

但为什么我们t类型被表示为Object类型呢?

 

事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 
    处理方法就是我们所提到的擦除(erased) 
    无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。
         如果泛型类型的类型变量没有限定(<T>) ,那么我们就用Object作为原始类型;
         如果有限定(<T extends XClass>),我们就XClass作为原始类型;
         如果有多个限定(<T extends XClass1&XClass2>),我们就用第一个边界的类型变量XClass1类作为原始类型; 

    比如上面的GenericClass<T>例子,编译器会把它当成被Object原始类型替代的普通类来替代。

所以现在可以知道为什么我们在使用list.add("dog")的时候会以Object类型装入容器了,因为List在被编译后原始类型被定义为Object了~

 

理解了泛型的声明侧和使用侧,也就知道该什么之后可以获取具体的泛型信息~

 

写的浑身都是汗。。重庆的天气~~哎

分享到:
评论

相关推荐

    Dephi泛型generic的应用 .mht

    Dephi泛型generic的应用 .mht

    C# 泛型(Generic)

    C# 泛型(Generic) 泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。 您可以通过数据...

    泛型(generic)

    泛型在编程中是一种强大的工具,特别是在C#和.NET框架中,它允许程序员创建可复用的类型安全的代码,可以处理多种数据类型。在上述示例中,我们看到两个不同的场景,一个是非泛型的堆栈实现,另一个是使用.NET框架中...

    11.4java-泛型(Generic).md

    11.4java-泛型(Generic)

    泛型演算法Generic Algorithms與Function Objects

    "泛型演算法Generic Algorithms與Function Objects"这个主题深入探讨了这一关键领域。 首先,让我们了解什么是泛型算法。泛型算法是一组不依赖于特定数据类型的操作,它们能在任何满足特定接口要求的对象上工作。...

    C#泛型类、泛型方法、泛型接口、泛型委托的实例

    例如,我们可以创建一个名为`GenericContainer&lt;T&gt;`的泛型类,其中`T`就是类型参数。这个类可以存储任何类型的对象,但具体类型在实例化时确定。这样做的好处是,我们无需为每种可能的数据类型创建单独的类,从而提高...

    泛型擦除(Generic erase)(教学视频+源代码)

    泛型擦除(Generic erase)(教学视频+源代码) 源代码中使用的泛型,在经过编辑后,代码中就看不到泛型,也就是所谓的泛型擦除 泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。...

    Generic_2(泛型类-泛型方法-泛型接口-泛型限定(上限)

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...

    C#泛型概念的简介与泛型的使用

    namespace _1_3_1泛型Generic { class DyArray { private T[] arr; //泛型数组 public int Lenght; //数组大小 //构造函数 public DyArray(int size) { this.Lenght = size; arr = new T[size]; } //向...

    java泛型数组

    ### Java 泛型数组的理解与应用 #### 一、引言 Java 泛型是 Java SE 5.0 引入的新特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。然而,在 Java 中创建泛型数组却...

    Generic_3(泛型限定(下限)-泛型限定(上限的体现)-泛型限定(下限的体现)-泛型限定(通配符的体现)-集合查阅的技巧)

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...

    实例讲解C# 泛型(Generic)

    C# 泛型(Generic)详解 C# 中的泛型(Generic)是一种增强程序功能的技术,主要用于延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。泛型允许您编写一个可以与任何数据类型一起工作...

    Jdk15泛型的实现

    早在JDK1.3时,随着GJ(Generic Java)的出现,Java社区开始探索泛型的可能性。GJ是一个支持泛型特性的Java编译器插件,为后续的泛型技术发展奠定了基础。到了JDK1.4,通过JSR#14的支持,泛型技术以插件的形式得到了...

    VC++ 2005:泛型编程

    在C++/CLI中声明泛型类或方法时,使用`generic &lt;typename T&gt;`关键字,其中`T`是类型参数。例如,可以创建一个泛型栈`Stack`,如下所示: ```cpp generic ref class Stack { public: void Push(ItemType item) {…}...

    Generic Programming(泛型程序设计小手册)

    Generic Programming(泛型程序设计小手册)中文chm版

    关于java的泛型.doc

    在这个示例中,`GenericClass`被声明为泛型类,其中`T`是类型参数。创建`GenericClass`的实例时,我们指定了`String`作为类型实参,因此`set`和`get`方法都只能接受或返回`String`类型的值。 ### 泛型通配符 泛型...

    数学和泛型编程-高效编程的奥秘(英文版pdf)原名:From_Mathematics_to_Generic_Programming

    数学和泛型编程-高效编程的奥秘(英文版pdf)原名:From_Mathematics_to_Generic_Programming,作者;Alexander A. Stepanov Daniel E. Rose

Global site tag (gtag.js) - Google Analytics