泛型(二)

1.泛型擦除

  虚拟机没有泛型类型对象——所有对象都属于普通类,所以无论何时定义一个泛型类型,都自动提供一个相应的原始类型,原始类型的名字就是删除类型参数后的泛型类型名。类型变量擦除有三种情况:

1.如果泛型类型的类型变量没有限定(<T>) ,那么我们就用Object作为原始类型;

例如:上一节我们使用Pair<T>的原始类型如下所示:

package generic;
/**
 * 泛型类
 * @author 堕落梦醒
 *
 * @param <Object>
 */
public class Pair {
    private Object first;
    private Object second;
    public Object getFirst() {
        return first;
    }
    public void setFirst(Object first) {
        this.first = first;
    }
    public Object getSecond() {
        return second;
    }
    public void setSecond(Object second) {
        this.second = second;
    }

    public Pair(Object first, Object second) {
        this.first = first;
        this.second = second;
    }
    public Pair() {

    }
}

2.如果有限定(<T extends XClass>),我们就XClass作为原始类型;

例如:

public class Interval<T extends Comparable> {
    private T lower;
    private T upper;
}

这个类的原始类型如下所示:

public class Interval {
    private Comparable lower;
    private Comparable upper;
}

3. 如果有多个限定(<T extends XClass1&XClass2>),我们就用第一个边界的类型变量XClass1类作为原始类型;

对于情况3,为了提供效率,我们应该讲标签接口(即没有方法的接口)放在列表的末尾。

2.翻译泛型表达式

  当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。例如,下面这个语句序列

Pair<Employee> pair = new Pair<Employee>();
Employee emp = pair.getFirst();

擦除getFirst的返回类型后将返回Object类型。编译器自动插入Employee的强制类型转换。也就是说,编译器把这个方法调用翻译为两条虚拟机指令:

1)对原始方法pair.getFirst()调用

2)  将返回的Object类型强制转换为Employee类型

3.翻译泛型方法(泛型在子类继承中的问题)

package generic;

import java.util.Date;

public class DateInterval extends Pair<Date>{

    public void setSecond(Date second) {
        super.setSecond(second);
    }
}

DateInterval 这个类想重写父类的setSecond方法,但是对于编译器并没有重写。因为pair类泛型擦除后setSecond(T second)变成了setSecond(Object second).但是DateInterval 类泛型擦除后setSecond方法还是setSecond(Date second)。两个方法的参数类型不一样,明显没有达到重写的要求,是两个不同的方法。这样就不能实现多态性了。

那么java编译器是如何解决这个问题的呢?编译器会在DateInterval类中生成一个桥方法。重写setSecond(Object second)方法,然后再方法里面调用setSecond(Date second)。

public void setSecond(Object second){
     setSecond((Date)second);
}

这样在多态调用时,调用的就是这个方法,达到了我们所期待的效果。

但桥方法有时也会带来问题,假设DateInterval类中也重写了getSecond方法:那么在泛型擦除后,就会有两个getSecond方法:

Date getSecond();  //在DateInteInterval中定义的

Object getSecond(); //编译器定义的桥方法

不能这样编写java代码,它们的方法名相同并且参数也相同。但是,在虚拟机中,用参数类型和返回类型确定一个方法,因此,编译器可能产生两个仅返回类型不同的方法字节码,虚拟机能够正确地处理这一情况。

4.java泛型转换的总结:

1.虚拟机中没有泛型,只有普通的类和方法。

2.所有的类型参数都用他们的限定类型替换。

3.桥方法被合成来保持多态。

4.为保持类型安全性,必要时插入强制类型转换。

时间: 2024-10-24 20:05:39

泛型(二)的相关文章

Java基础系列:(1)关于泛型的简单总结

一 为什么要引入泛型这个概念? 这里我用一个实例来简单说明.比如说:我们要设计一个表示二维坐标的类,但是因为关于坐标的表示有多种形式,比如: (1)整数表示:x=10    y=20 (2)浮点型表示:x=10.5    y=20.8 (3)字符串表示:x=""东经 50度""    y="北纬 79度" 因此,在我们设计的类中就不能单一的设置成int,float或String,而想要使用一个类型来接收这三种不同的数据类型,就只能使用Object

OC的泛型使用介绍

一.泛型的介绍 1.泛型就是没有规定类型,在使用的时候决定类型 2.最早的泛型是C++ template 3.c#将泛型发挥的淋漓尽致 4.swift中首次引用泛型 5.新的xcode 在swift影响下给OC加入了泛型(违泛型) 二.泛型的使用 1.泛型的作用就是可以限制内容的类型 2.正常的情况下,数组中存放的是id对象,如果我们想也要使用点语法,必须进行强转. 3.如果我们使用泛型的话,可以限制里面的内容,如果传入的不是Person类型的对象就会有警告 4.好处:我们可以直接通过点语法访问

第六节:Java泛型

Java 泛型完全解读 阅读目录 一.为什么会出现泛型 二.泛型会带来什么样的问题 1. 不能用基本类型实例化类型参数 2. 不能用于运行时类型检查 3. 不能创建类型实例 4. 不能静态化 5. 不能抛出或捕获泛型类的实例 6. 不允许作为参数进行重载 7. 不能创建泛型数组 三.边界拓展 1. 无界通配符 2. 上界 3. 下界 4. PECS 原则 5. 自限定类型 总结 对于泛型的使用我想大家都非常熟悉,但是对于类型擦除,边界拓展等细节问题,可能不是很清楚,所以本文会重点讲解一下:另外对

Java基础加强-反射、注解

基础加强 一回顾泛型 二泛型的反射 三注解 基础加强 一.回顾泛型 泛型的基本概念: 以ArrayList<E>为例: ① ArrayList<E>中的E称为类型参数变量 ArrayList<Integer>中的Integer称为实际类型参数 ②整个ArrayList<E>称为泛型类型 整个ArrayList<Integer>称为参数化的类型(ParameterizedType) 定义一个泛型方法: : // <T>:泛型定义的声明,

蓝鸥Unity开发基础二——课时21 泛型

本节课我们来学习C#中的泛型,泛型是一个特殊的类型,它可以最大限度的重用我们的代码! 推荐视频讲师博客:http://11165165.blog.51cto.com/ 使用泛型能够最大限度的重用代码,保护类型安全,提高性能 泛型成员因为类型的不确定性,不能使用算术运算符,比较运算符 类型参数可以有多个,可以是编译器能够识别的任何类型 类型参数的名字不能够随便起,不能重名 一.数组类Array using System; namespace Lesson_21{    //数组类Array    

【转载】Java泛型(二)

转自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest { 2 3 public static void main(String[] args) { 4 List list = new ArrayList(); 5 list.add("qqyumidi"); 6 list.add("corn&qu

泛型全面分析和应用(二)

接着上篇文章,我们介绍了很多有关于泛型使用和注意的事项,这次将给一个很好的代码实例来演示泛型的有趣性----代码来着<Java编程思想> 例子一:再来一杯coffee 代码的思路如下: 构建一个Generator的接口,这个接口用来实现“繁殖功能”的作用 定义一个Coffee类,接着用几种Coffee子类继承这个Coffee父类 构建一个CoffeeGenerator的类,这个类有两个特点,一个是实现了Generator<Coffee>和Iterable<Coffee>

菜鸟译文(二)——使用Java泛型构造模板方法模式

如果你发现你有很多重复的代码,你可能会考虑用模板方法消除容易出错的重复代码.这里有一个例子:下面的两个类,完成了几乎相同的功能: 实例化并初始化一个Reader来读取CSV文件: 读取每一行并解析: 把每一行的字符填充到Product或Customer对象: 将每一个对象添加到Set里: 返回Set. 正如你看到的,只有有注释的地方是不一样的.其他所有步骤都是相同的. ProductCsvReader.java public class ProductCsvReader {       Set<

java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题

java泛型(二).泛型的内部原理:类型擦除以及类型擦除带来的问题 参考:java核心技术 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首要前提是理解类型擦出(type erasure). Java中的泛型基本上都是在编译器这个层次来实现的.在生成的Java字节码中是不包含泛型中的类型信息的.使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉.这个过程就称为类型