Java泛型详解

栏目: Java · 发布时间: 7年前

内容简介:Java泛型详解

泛型是 Java 5引入的机制, 允许编写不关心具体类型的类或方法. 泛型最著名的应用是 Collection 框架.

List<String> list = new ArrayList<>();

泛型类 List 在定义时并不关心元素类型, 只有在实例化时才获得具体的元素类型.

泛型类

声明泛型需要使用 <> 声明类型参数, 如 <T> , <T1, T2> . 下面的示例中声明了一个 Holder 类, 它的item域可以存储任意类型的引用.

class Holder<T> {

    T item;

    publicvoidset(T t) {
        item = t;
    }

    public T get() {
        return item;
    }

    publicstaticvoidmain(String[] args) {
        Holder<String> holder = new Holder<>();
        holder.set("Hello World");
        System.out.println(holder.get());
    }
}

在Java 7之前必须在创建实例时指定类型参数:

Holder<String> holder = new Holder<String>();

Java 7提供了类型推断功能, 可以根据声明推断实例的类型参数:

Holder<String> holder = new Holder<>();  // 不必在new对象时再写一次类型参数了

或者在 return 时推断类型:

publicstatic Holder<String> getInstance() {
    return new Holder<>();
}

示例中的 Holder 类没有对类型参数T做任何限制, T可以实例化为任意类型. Java允许我们限制对其进行限制.

  • <T extends MyClass> : T必须为 MyClass 或其子类

  • <T super MyClass> : T必须为 MyClass 或其父类

比较常用的是 extends 限定, 因为子类必然定义了父类的方法(和域), 因此我们可以安全地访问父类声明的方法(和域).

下面的示例中访问 item.length() 是安全的, 因为 T 的基类 String 定义了该方法.

class Holder<T extends String> {

    T item;

    publicvoidset(T t) {
        item = t;
    }

    public T get() {
        return item;
    }

    publicintlength() {
        return item.length();
    }

    publicstaticvoidmain(String[] args) {
        Holder<String> holder = new Holder<>();
        holder.set("Hello World");
        System.out.println(holder.length());
    }

}

泛型方法

Java也允许只为方法而非整个类声明类型参数:

public class Main {

    public static <T> voidlog(T t) {
        System.out.println(t);
    }
    
    publicstaticvoidmain(String[] args) {
        log(1);
    }
}

类型通配符

在上文示例中, 我们总是在实例化泛型类时指定具体的类代替类型参数, 比如 Holder<String> 使用 String 代替类型参数 T .

类型通配符允许在实例化泛型类时不指定具体类:

Holder<?> holder = new Holder<>();

上述示例初始化了一个没有类型限制的 Holder 实例. 无任何限制的类型通配符可以被省略:

Holder holder = new Holder();

除非因为绝对必要的原因, 否则不建议使用无限制的类型通配符. 类型通配符同样可以使用 extendssuper 进行范围限定.

Holder<? extends String> holder = new Holder<>();

上述示例中, holderset 方法不能正常编译. 类型通配符通常用于声明方法的参数类型:

class Holder<T> {

    T item;

    publicvoidset(T t) {
        item = t;
    }

    public T get() {
        return item;
    }

    publicstaticvoidprint(Holder<? extends String> holder) {
        System.out.println(holder.get());
    }

    publicstaticvoidmain(String[] args) {
        Holder<String> holder = new Holder<>();
        holder.set("Hello World");
        print(holder);
    }

}

类型擦除

java的泛型采用运行时类型擦除的方式实现泛型, 也就是说类型参数仅存在于编译期, 运行时虚拟机并不知道泛型参数的存在.

publicstaticvoidmain(String[] args) {
    List<String> strings = new ArrayList<>();
    List<Long> longs = new ArrayList<>();
    System.out.println(strings.getClass() == longs.getClass());
}

上文示例输出 true , 说明了运行期无法访问类型参数. 泛型是通过编译时添加了类型检查和自动转型的字节码来实现的.

数组也受到了类型擦除影响:

public class Main {

    public static <T> voidprint(T[] arr) {
        for (T t : arr) {
            System.out.println(t);
        }
    }

    publicstaticvoidmain(String[] args) {
        String[] strings = {"a", "b", "c", "d"};
        print(strings);
    }
}

上面的代码是可以正常运行的, 但是Java禁止直接创建泛型数组:

public static <T> voidtest() {
        T[] arr = new T[5];
    }

禁止创建泛型数组的原因可以在 Java Language Specification 中窥见端倪:

10.6 数组初始化 中提到

[It is a compile-time error if the component type of the array being initialized is not reifiable(4.7)

看一下reifiable(物化)的 定义 :

A type is reifiable if and only if one of the following holds:

It refers to a non-generic class or interface type declaration.

It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).

It is a raw type (§4.8).

It is a primitive type (§4.2).

It is an array type (§10.1) whose element type is reifiable.

因为类型擦除的原因, java.util.ArrayList 采用了 Object[] 来存储元素.

本文永久更新链接地址 http://www.linuxidc.com/Linux/2018-01/150360.htm


以上所述就是小编给大家介绍的《Java泛型详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

娱乐至死

娱乐至死

[美] 尼尔·波兹曼 / 章艳 / 广西师范大学出版社 / 2011-6 / 29.80元

《娱乐至死》是对20世纪后半叶美国文化中最重大变化的探究和哀悼:印刷术时代步入没落,而电视时代蒸蒸日上;电视改变了公众话语的内容和意义;政治、宗教、教育和任何其他公共事务领域的内容,都不可避免的被电视的表达方式重新定义。电视的一般表达方式是娱乐。一切公众话语都日渐以娱乐的方式出现,并成为一种文化精神。一切文化内容都心甘情愿地成为娱乐的附庸,而且毫无怨言,甚至无声无息,“其结果是我们成了一个娱乐至死......一起来看看 《娱乐至死》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具