泛型

作者: 于无声处写写写 | 来源:发表于2018-07-15 10:30 被阅读21次

只标记重要的部分


什么是泛型?

泛型即参数化类型,参数化类型就是说将类型由原来具体给定的某一个类型参数化,也就是说现在的类型是一个参数,由这个参数决定到底是什么类型。
JavaSE7及以后,构造函数中可以省略泛型类型:

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

类型变量放在修饰符的后面,返回类型的前面。

class ArrayAlg
{
    public static <T> T getMiddle(T...a)
    {
        return a[a.length/2];
    }
}

类型变量的限定

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

表示T是Comparable类型的子类型,一个类型变量或通配符可以有多个限定
限定类型用&分隔,逗号用来分隔类型变量
可以有多个接口超类型,但是限定中至多有一个类。
如果用一个类作为限定,它必须是限定列表中的第一个。


泛型代码和虚拟机

虚拟机没有泛型类型对象---所有对象都属于普通类
在虚拟机中,无论何时定义一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型参数后的泛型类类名。
Pair<T>的原始类型为Pair

Java泛型转换的事实:

  • 虚拟机中没有泛型,只有普通的类和方法。
  • 所有的类型参数都用他们的限定类型替换
  • 桥方法被合成来保持多态
  • 为保持类型安全性,必要时插入强制类型转换

使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来最基本的类型,举个栗子也就是Pair<T>的原始类型为Pair,原因在于java泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说成功编译过后的class文件是不包含任何泛型信息的,泛型信息不会进入到运行阶段,不会进入虚拟机运行阶段。

  • 对此总结成一句话,泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。

约束与局限性

  • 不能用基本类型实例化类型参数,因此没有Pair<double>,只有Pair<Double>
  • 虚拟机中的对象总有一个特定的非泛型类型。因此所有的类型查询只产生原始类型。
  • 试图查询一个对象是否属于某个泛型类型时,倘若使用instanceof会得到一个编译器错误,如果使用强制类型转换会得到一个警告。
  • 不能创建参数化类型的数组
  • 泛型类的静态上下文中类型变量无效
public class Singleton<T>
{
  private static T singleInstance();
}

上述是无效的

  • 既不能抛出也不能捕获泛型类对象,甚至泛型类扩展Throwable都是不合法的
public class Problem<T> extends Exception
  • 一个类或者类型变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化。如下
class Employee implements Comparable<Employee>{}
class Manager extends Employee implements Comparable<Manager>{}

Manager会实现Comparable<Employee>和Comparable<Manager>,这是同一接口的不同参数化。

  • 带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。
  • 通配符不是类型变量,因此不能在代码中使用“?”作为一种类型
  • 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。

在逻辑上Box<Number>不能视为Box<Integer>的父类。因为在编译阶段以后会进行类型擦除,都成了Box类

  • 只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

    • 这才是一个真正的泛型方法。
    • 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
    • 这个T可以出现在这个泛型方法的任意位置.
    • 泛型的数量也可以为任意多个
    • 如:public <T,K> K showKeyName(Generic<T> container){}
  • 类中的泛型方法
    //在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
    //由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
    public <E> void show_3(E t){
    System.out.println(t.toString());
    }
    在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。
    public <T> void show_2(T t){
    System.out.println(t.toString());
    }

  • //在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加
    //public <T> T showKeyName(Generic<T extends Number> container),编译器会报错:"Unexpected bound"

  • 下面的声明则不会报错
    public <T extends Number> T showKeyName(Generic<T> container){

相关文章

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

  • 【Swift】泛型常见使用

    1、Swift泛型4种 泛型函数泛型类型泛型协议泛型约束 2、泛型约束3种 继承约束:泛型类型 必须 是某个类的子...

网友评论

    本文标题:泛型

    本文链接:https://www.haomeiwen.com/subject/ommspftx.html