Java核心技术知识点笔记—泛型程序设计(二)

1、泛型方法:

(1)定义:泛型方法的定义方式,将类型变量放在修饰符的后面,返回类型的前面。

public class TestGenericC {

    public  void test(T t) {
        System.out.print(t);
    }
}

如上,在一个普通类中定义了一个泛型方法。

(2) 调用:当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:

public class Main {
    public static void main(String[] args) {
        TestGenericC genericC = new TestGenericC();
        genericC.test("generic test");
    }
}

大多数情况下,尖括号中的类型参数可以省略,编译器有足够的信息能够推断出所调用的方法。(如上例,编译器使用names的类型(即String[])与泛型类型T[]进行匹配并推断出T一定是String。)

2、泛型代码和虚拟机

虚拟机没有泛型类型对象:所有对象都属于普通类。

2.1、类型擦除:定义一个泛型类型都自动提供了一个相应的原始类型(raw type)。原始类型的名字就是删去类型参数后的泛型类型名。擦除(erased)类型变量,并替换为限定类型(无限定的用Object替换)。

public class TestGenericC { //泛型类型
    private T first;
    private T second;
}

public class TestGenericC{ //原始类型
    private Object first;
    private Object second;
}

如上所示,TestGenericC的泛型类型T没有限定,因此它的原始类型用Object来替换。如果对T有所限定,则使用第一个限定的类型变量来替换。如:

public class TestGenericC { //泛型类型
    private T first;
    private T second;
}

public class TestGenericC{ //原始类型
    private Comparable first;
    private Comparable second;
}

对类型T做了限定,原始类型中使用第一个限定类型Conparable来进行替换。为了提高效率,应该将标签(tagging)接口(没有方法的接口)放在边界列表的末尾。

2.2、翻译泛型表达式:当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。例如:

public class TestGenericC { //泛型类型
    private T first;

    public T getFirst() {
        return first;
    }
}

public class Main {
    public static void main(String[] args) {
        TestGenericC genericC = new TestGenericC();
        String first = genericC.getFirst();
    }
}

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

(1)对原始方法TestGenericC.getFirst的调用;

(2)将返回的Object类型强制转换为String类型。

当存取一个泛型域时(如上例的first)一样要插入强制类型转换。

2.3、翻译泛型方法:(详见:《Java核心技术》卷1(原书第10版)第318页)

2.4、注意点:

(1)虚拟机中没有泛型,只有普通的类和方法;

(2)所有的类型参数都用它们的限定类型替换;

(3)桥方法被合成来保持多态;

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

你可能感兴趣的:(Java,java,泛型方法,泛型擦除)