基础---java 泛型

一、介绍部分 

定义:

       java泛型是javaSE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法和构造器(constructor。 


 好处:

1、类型安全。 泛型的主要目标是提高 Java 程序的类型安全,取消类型转换,减少发生错误的机会。

2、消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3、潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。


关键词:

? 通配符,任意类型,不能用于声明泛型。
T  K V E 都可以,表示普通类型。用于声明泛型,指的是某个确定类型,在实例化或者调用的时候需要指定。

普通类型或者类型加上 extends或者super构成受限类型,上限类型,下限类型。(? extends/T extends)

总结 ? extends 和 ? super 通配符的特征,我们可以得出以下结论:

  • 如果你想从一个数据类型里获取数据,使用? extends 通配符
  • 如果你想把对象写入一个数据结构里,使用? super 通配符
  • 如果你既想存,又想取,那就别用通配符。

这就是Maurice Naftalin在他的《Java Generics and Collections》这本书中所说的存取原则,以及Joshua Bloch在他的《Effective Java》这本书中所说的PECS法则。

这PECS是指”Producer Extends, Consumer Super”,这个更容易记忆和运用。


特殊性:

Java泛型实现原理:类型擦除,  Java的泛型是伪泛型。在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure

java泛型(Generic[dʒəˈnɛrɪk] Type)只存在于java源码之中,一旦编译成字节码(.class文件),就会被替换为原始类型(Raw[rɔ] Type--裸类型),并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类(ArrayList)。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。

那么这就有个问题了,既然在编译的时候会在方法和类中擦除实际类型的信息,那么在返回对象时又是如何知道其具体类型的呢?如List<String>编译后会擦除掉String信息,那么在运行时通过迭代器返回List中的对象时,又是如何知道List中存储的是String类型对象呢?      擦除在方法体中移除了类型信息,所以在运行时的问题就是边界即对象进入和离开方法的地点,这正是编译器在编译期执行类型检查并插入转型代码的地点。泛型中的所有动作都发生在边界处:对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型

Java语法糖会在后面博文中介绍学习

二、举例说明

1、根据泛型存在的位置分为:泛型类、泛型接口、泛型方法

a. 泛型类

class Point<T>{
   private T var;
 ...
}
b.泛型接口

public interface Points<T>{
    public T getValue();
}

c.泛型方法(泛型的声明,必须在方法的修饰符(public,static,final,abstract等)之后,返回值声明之前)
 public static <T> void display(T t) {
        System.out.println(t.getClass());
}
是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。

使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。

最后,需要注意的是,一个static方法,无法访问泛型类的类型参数,因为类还没有实例化,所以,若static方法需要使用泛型能力,必须使其成为泛型方法。



注意事项:

1)方法重载

在JAVA里面方法重载是不能通过返回值类型来区分的,比如代码一中一个类中定义两个如下的方法是不容许的。但是当参数为泛型类型时,却是可以的。如下面代码二中所示,虽然形参经过类型擦除后都为List类型,但是返回类型不同,这是可以的

2)泛型类型是被所有调用共享的

       所有泛型类的实例都共享同一个运行时类,类型参数信息会在编译时被擦除。因此考虑如下代码,虽然ArrayList<String>和ArrayList<Integer>类型参数不同,但是他们都共享ArrayList类

3)instanceof

不能对确切的泛型类型使用instanceOf操作。如下面的操作是非法的,编译时会出错。

4)泛型数组问题

不能创建一个确切泛型类型的数组。如下面代码会出错。

List<String>[] lsa = new ArrayList<String>[10];//compile error.

5)泛型类并没有自己独有的Class类对象。

比如并不存在List<String>.class或是List<Integer>.class,而只有List.class。

6)静态变量是被泛型类的所有实例所共享的。

对于声明为MyClass<T>的类,访问其中的静态变量的方法仍然是 MyClass.myStaticVar。不管是通过new MyClass<String>还是new MyClass<Integer>创建的对象,都是共享一个静态变量。

7)泛型的类型参数不能用在Java异常处理的catch语句中。

因为异常处理是由JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分两个异常类型MyException<String>和MyException<Integer>的。对于JVM来说,它们都是 MyException类型的。也就无法执行与异常对应的catch语句。



思考问题:

泛型与之类型问题

比如一个方法如果接收List<Object>作为形式参数,那么如果尝试将一个List<String>的对象作为实际参数传进去,却发现无法通过编译。虽然从直觉上来说,Object是String的父类,这种类型转换应该是合理的。但是实际上这会产生隐含的类型转换问题,因此编译器直接就禁止这样的行为。


应用实例:未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值