JAVA基础之泛型程序设计《二》

JAVA基础之泛型程序设计《二》

1. 泛型代码与虚拟机
1.1 类型擦除

​ 无论何时定义一个泛型类,虚拟机都会提供一个相应的原始类型。这个原始类型名就是去掉类型参数后的的泛型类型名。类型变量会被擦除,并替换为限定类型(无限定类型则替换为Object)。如果有多个限定类型则选择第一个

// 泛型类
class Animal<T>{
    private T obj;

    public T getObj() {
        return obj;
    }
}
// 经过虚拟机转换
class Animal{
    private Object obj;

    public Object getObj() {
        return obj;
    }
}

1.2 转换泛型表达式

​ 编写一个泛型方法,并且返回类型是类型变量,调用时,虚拟机会擦除返回类型,这时编译器会插入强制类型转换。如下

Pir<Employee> buddies = ...;
Employee buddy = buddies.getFirst();

getFirst()获取 First 字段。类型擦除时,返回类型变为Object,编译器会自动插入Employee的强制类型转换。

2.3 转换泛型方法

​ 类型擦除也会出现在泛型方法中。如果有限定类型则由限定类型代替

泛型方法:

public static <T extend Comparable> T min(T[] a)

擦除之后:

public static Comparable min(Comparable[] a)

由于擦除类型变量之后,泛型方法返回类型会变成Object,但是当一个类继承一个泛型类时,调用超类的方法,且这个超类的这个方法参数类型为类型变量,子类为具体类型变量。擦除之后,超类的这个方法参数类型 T 变成 Object 而子类调用超类该方法传入的参数为其它类型的参数。此时系统会合成乔方法来解决该问题。如下例题

package priv.zsl.template;

/**
 * @author m1767
 */
@SuppressWarnings("all")
public class InheritT {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Biology<Mouse> biology = animal;
        Mouse mouse = new Mouse();
        biology.setName(mouse);
        System.out.println(biology);
    }
}

@SuppressWarnings("All")
class Animal extends Biology<Mouse>{

    public void setName(Mouse mouse) {
        super.setName(mouse);
    }
}
@SuppressWarnings("All")
class Biology<T> {
    private T name;
    public void setName(T animal) {
        this.name = animal;
        System.out.println(this.name);
    }
}
class Mouse {
    @Override
    public String toString() {
        return super.toString();
    }
}

运行结果

//priv.zsl.template.Mouse@14ae5a5
//priv.zsl.template.Animal@7f31245a

可见输出没有错误,正常输出。

查看bytecode:

// class version 52.0 (52)
// access flags 0x20
// signature Lpriv/zsl/template/Biology<Lpriv/zsl/template/Mouse;>;
// declaration: priv/zsl/template/Animal extends priv.zsl.template.Biology<priv.zsl.template.Mouse>
class priv/zsl/template/Animal extends priv/zsl/template/Biology {

  // compiled from: InheritT.java

  // access flags 0x0
  <init>()V
   L0
    LINENUMBER 18 L0
    ALOAD 0
    INVOKESPECIAL priv/zsl/template/Biology.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lpriv/zsl/template/Animal; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public setName(Lpriv/zsl/template/Mouse;)V
   L0
    LINENUMBER 21 L0
    ALOAD 0
    ALOAD 1
    INVOKESPECIAL priv/zsl/template/Biology.setName (Ljava/lang/Object;)V
   L1
    LINENUMBER 22 L1
    RETURN
   L2
    LOCALVARIABLE this Lpriv/zsl/template/Animal; L0 L2 0
    LOCALVARIABLE mouse Lpriv/zsl/template/Mouse; L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x1041
  //系统生成的乔方法。
  public synthetic bridge setName(Ljava/lang/Object;)V
   L0
    LINENUMBER 17 L0
    ALOAD 0
    ALOAD 1
    CHECKCAST priv/zsl/template/Mouse
    INVOKEVIRTUAL priv/zsl/template/Animal.setName (Lpriv/zsl/template/Mouse;)V
    RETURN
   L1
    LOCALVARIABLE this Lpriv/zsl/template/Animal; L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 2
}

所以泛型方法在类的继承中,系统会自动生成桥方法:

​ 所以子类具有俩个同样的方法。

 
 public void setName(Mouse mouse) {
        ......
    }
public void setName(Object ...) {
        ....
    }

所以泛型方法在类的继承中,系统会自动生成桥方法:

​ 所以子类具有俩个同样的方法。

 
 public void setName(Mouse mouse) {
        ......
    }
public void setName(Object ...) {
        ....
    }

由于虚拟机可以通过返回类型和参数类型不一样来识别俩个同名方法,但是在编写java方法时不合法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值