前几天在看撒加老师早期的一些关于泛型的回复,对于泛型深有体会,略作小结。
对于泛型来说,这个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
C# 泛型(Generic) 泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。 您可以通过数据...
泛型在编程中是一种强大的工具,特别是在C#和.NET框架中,它允许程序员创建可复用的类型安全的代码,可以处理多种数据类型。在上述示例中,我们看到两个不同的场景,一个是非泛型的堆栈实现,另一个是使用.NET框架中...
11.4java-泛型(Generic)
"泛型演算法Generic Algorithms與Function Objects"这个主题深入探讨了这一关键领域。 首先,让我们了解什么是泛型算法。泛型算法是一组不依赖于特定数据类型的操作,它们能在任何满足特定接口要求的对象上工作。...
例如,我们可以创建一个名为`GenericContainer<T>`的泛型类,其中`T`就是类型参数。这个类可以存储任何类型的对象,但具体类型在实例化时确定。这样做的好处是,我们无需为每种可能的数据类型创建单独的类,从而提高...
泛型擦除(Generic erase)(教学视频+源代码) 源代码中使用的泛型,在经过编辑后,代码中就看不到泛型,也就是所谓的泛型擦除 泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。...
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
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 SE 5.0 引入的新特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。然而,在 Java 中创建泛型数组却...
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
C# 泛型(Generic)详解 C# 中的泛型(Generic)是一种增强程序功能的技术,主要用于延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。泛型允许您编写一个可以与任何数据类型一起工作...
早在JDK1.3时,随着GJ(Generic Java)的出现,Java社区开始探索泛型的可能性。GJ是一个支持泛型特性的Java编译器插件,为后续的泛型技术发展奠定了基础。到了JDK1.4,通过JSR#14的支持,泛型技术以插件的形式得到了...
在C++/CLI中声明泛型类或方法时,使用`generic <typename T>`关键字,其中`T`是类型参数。例如,可以创建一个泛型栈`Stack`,如下所示: ```cpp generic ref class Stack { public: void Push(ItemType item) {…}...
Generic Programming(泛型程序设计小手册)中文chm版
在这个示例中,`GenericClass`被声明为泛型类,其中`T`是类型参数。创建`GenericClass`的实例时,我们指定了`String`作为类型实参,因此`set`和`get`方法都只能接受或返回`String`类型的值。 ### 泛型通配符 泛型...
数学和泛型编程-高效编程的奥秘(英文版pdf)原名:From_Mathematics_to_Generic_Programming,作者;Alexander A. Stepanov Daniel E. Rose