一

{"type":"编程笔记"}


  • Home

  • Archives
  • Search

java泛型相关知识点

Posted on 2012-10-10   |   In java

一、java泛型基本概念

泛型(Generic Type或Generics)是对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看做是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的占位符一样,泛型的体现主要是在集合框架里面可以看到,JCF里面应该是1.5里面使用泛型最多的地方。Java语言引入泛型是一个较大的功能增强,不仅语言、类型系统和编译器有了大变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为了泛型化的了。

Java语言中的泛型基本上完全在编译器中实现,由编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码。这种实现技术称为擦除(erasure,编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)。

二、什么是类型擦除

类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。

类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

具体的转化过程大致分为以下几个部分:

  1. 将参数化类型中的类型参数擦除(erasure)掉;
  2. 将类型变量用上限(upper bound)取代,通常情况下这些上限是Object。这里的类型变量是指实例域,本地方法域,方法参数以及方法返回值中用来标记类型信息的变量,例如:实例域中的变量声明A elem;,方法声明Node (A elem){};,其中,A用来标记elem的类型,它就是类型变量。
  3. 添加类型转换并插入桥方法(bridge method),以便覆盖(overridden)可以正常的工作。

三、泛型优点

  1. 类型安全。泛型的一个主要目标就是提高Java程序的类型安全。使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果没有泛型,那么类型的安全性主要由程序员来把握,这显然不如带有泛型的程序安全性高。
  2. 消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。

四、泛型的类型限制

JSR-14中规定:

  1. 不应在静态成员中引用封闭类型参数
  2. 不能用基本类型实例化泛型类型参数
  3. 不能在数据类型转换或instanceof操作中使用类型参数
  4. 不能在new操作符中使用类型参数
  5. 不能在类定义的implements或extends子句中使用类型参数

五、泛型和反射

既然泛型信息在编译后已完全抹去,那如何在运行时得到参数化的类型呢?

泛型是在Java平台上作为编译时转换实现的。编译器实际上生成与使用非泛型源代码时相同的字节指令,插入运行时类型转换以在每次访问时将值转换为正确的类型。尽管是相同的字节码,但是类型参数信息用一个新的签名(signature)属性记录在类模式中。JVM在装载类时记录这个签名信息,并在运行时通过反射使它可用。

六、通配符类型和受限泛型

通配符,使用一个?标识类型参数,是一种表示类或方法行为对于未知类型的类型约束的方法,比如“不管这个方法的参数x和y是哪种类型,它们必须是相同的类型”。

通配符类型List<?>、List<T>、原始List和具体List<Object>都不相同。如果说变量x具有List<?>类型,标识存在一些T类型,其中x是List<T>类型。

尽管我们不知道其元素的具体类型,这并不代表它具有任意内容,而是指我们并不了解内容的类型限制是什么--但我们知道存在某种限制。

另一方面,原始类型List是异构的,我们不能对其元素有任何类型限制,具体类型List<Object>表示我们明确地知道它能包含任何对象。

在非?通配符的使用过程里面,一般的通配符如T相当于是定义了一个类型,该类型是可以直接作为Java语言里面的类型来进行使用的,在定义这种类型的泛型类里面可以直接使用。

七、泛型不是协变(covariant)的,而数组则是协变的

数组是协变的,因为Integer是Number的子类型,数组类型Integer[]是Number[]的子类型,因此在任何需要Number[]值的地方都可以提供一个Integer[]值。

泛型不是协变的,List<Integer>不是List<Number>的子类型,试图在要求List<Number>的位置提供List<Integer>是一个类型错误。

因为数组和泛型的这个冲突,所以java语法规定不能创建参数化类型组成的数组,因为这样的数组会破坏类型的安全性。

java不允许这样的写法:List<Integer>[] list = new ArrayList<Integer>[]{};

但是List<Integer>[]本身可以作为类型参数,如:List<List<Integer>[]> list = new ArrayList<List<Integer>[]>();

另外未绑定的参数化类型数组new ArrayList<?>[3]是合法的,因为ArrayList<?>是可具化类型(reifiable type)。

Read more »

vim converting tabs to spaces

Posted on 2012-10-09   |   In vim

将文件中的tab转化为空格。

Read more »

java的jps命令

Posted on 2012-09-26   |   In java

功能

jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid,启动命令和参数的命令。

The jps command uses the java launcher to find the class name and arguments passed to the main method. If the target JVM is started with a custom launcher, the class name (or JAR file name) and the arguments to the main method will not be available. In this case, the jps command will output the string Unknown for the class name or JAR file name and for the arguments to the main method.

原理

java程序在启动以后,会在java.io.tmpdir指定的目录下,生成一个类似于hsperfdata_<UserName>的文件夹,其中有几个文件,名字就是java进程的pid,这个文件夹是与当前用户关联的,所以jps仅查找当前用户的Java进程,而不是当前系统中的所有进程。

java.io.tmpdir的位置可以用如下命令显示:

 mvn help:system
Read more »

关于java的受检异常

Posted on 2012-09-25   |   In java

java语言中的异常是一个Throwable对象,其下又分二个子类:Error,Exception,Exception又可以分为受检异常和运行时异常(非受检异常),CheckedException/UncheckedException。

一般Error都是系统级别的错误,一般自定义异常都是继承自Exception,而不要去继承Error。

程序如果抛出Error,不用管它,让JVM去处理吧,如OutOfMemoryError。因此代码中不要出现catch Throwable的写法。

对于受检异常和非受检异常,java有不同的处理规则,如果调用方法签名中使用的是非受检异常,调用者可以不必在代码中捕获它,也不需要在方法签名中声明它。如果调用方法签名里使用了throws子句声明了受检异常,那调用者就被迫对此异常要进行捕获或者在自已的方法签名中声明它们。

编译器也会自动告诉你,调用方法中是否有抛出受检异常。

Effective Java作者Joshua Bloch的观点

  1. 只有在需要捕获异常的情况下才使用异常,不应该用于正常的控制流,优先使用标准的,易理解的模式,如下代码示例一。
  2. 设计良好的API可以通过提供状态检测方法,来避免强迫客户端程序员为了正常的控制流而使用异常,如下代码示例二。
  3. 对可恢复的情况使用受检异常,对编程错误使用运行时异常。(这个说法是正确的,而问题是在于有多少抛出来的受检异常可恢复?又恢复了多少?因此Bloch马上又提到了下面这条准则)。
  4. 避免不必要地使用受检异常。这个在语言设计而言,是一个很好的特性,能强迫程序员处理异常,增强了可靠性,但会使API使用起来非常不方便,给程序员增添了不可忽视的负担。
  5. 在使用到异常的地方,优先使用标准异常而不是自定义异常,这样会使你的代码更具可读性(因为标准异常大家都熟悉),同时也减少了异常类。
  6. 每个抛出异常的方法都要有文档说明,说明抛出异常的条件,对于会抛出运行时异常的方法,可以在文档中描述方法被成功执行的前提条件和代码调用示例。
  7. 提供足够多的异常信息,不要吞掉异常。
  8. 保持异常的原子性,将对象恢复到调用之前的状态。
  9. 不要忽略异常。
Read more »

introduction to xmlhttprequest level 2

Posted on 2012-09-21   |   In javascript

老版本的XMLHttpRequest对象有以下几个缺点

  • 只支持文本数据的传送,无法用来读取和上传二进制文件。
  • 传送和接收数据时,没有进度信息,只能提示有没有完成。
  • 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。

新版本的XMLHttpRequest对象,针对老版本的缺点,做出了大幅改进

  • 可以设置HTTP请求的时限。
  • 可以使用FormData对象管理表单数据。
  • 可以上传文件。
  • 可以请求不同域名下的数据(跨域请求)。
  • 可以获取服务器端的二进制数据。
  • 可以获得数据传输的进度信息。
Read more »
1…363738…99
yuweijun

yuweijun

492 posts
12 categories
RSS
GitHub Twitter
© 2021 yuweijun
Powered by Hexo
Theme - NexT.Mist.KISS