浅谈java泛型

Posted Al_tair

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈java泛型相关的知识,希望对你有一定的参考价值。

常用集合类

大家好呀!我是小笙!我学习了韩顺平老师的类和对象的知识,收获颇丰!现在来和大家分享笔记!

基本介绍

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型特点

  • 可以使用任意字母A-Z T 是 type的缩写,比较常用

    // 自定义泛型
    class Template<E>
        E filed;
    
        @Override
        public String toString() 
            return "Template" +
                    "filed=" + filed +
                    '';
        
    
        public E method()
            return filed;
        
    
        public Template(E filed) 
            this.filed = filed;
        
    
    
  • 只能指代引用类型的数据

  • 在给泛型指定具体类型后,可以传入该类型或者其子类类型

    public class Generic02 
        public static void main(String[] args) 
            C<A> C = new C<A>(new A());
            C<A> C2 = new C<A>(new B());
        
    
    class A
    class B extends A
    class C<E>
        E c;
    
        public C(E c) 
            this.c = c;
        
     
    
  • 泛型的使用形式

    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    ArrayList<Integer> arrayList2 = new ArrayList<>(); // 推荐
    ArrayList arrayList = new ArrayList(); // 默认泛型为Object
    

分析泛型编译后的文件

java里面的泛型只存在于源代码里面,一旦经过编译之后,所有的泛型都会被擦除掉,全部被替换为原来的裸类型,并在对元素进行访问和修改的时候,才会加上强制类型转换。

// (所谓的裸类型指的是,ArrayList<Integer>() 他的裸类型就是ArrayList())
public class Test 
    public static void main(String[] args) 
        ArrayList<String> sList = new ArrayList<String>();
        ArrayList<Integer> iList = new ArrayList<Integer>();
        // getClass()方法 表示此对象的运行时类的Class对象
        System.out.println(sList.getClass() == iList.getClass()); // true
    

// 代码
public class Generic02 
    public static void main(String[] args) 
        C<A> C = new C<A>(new A());
        C<A> C2 = new C<A>(new B());
        A a = C.c;
    

class A
class B extends A
class C<E>
    E c ;
    E[] e;
    public C(E c) 
        this.c = c;
    

// 反编译代码  IDEA 选中代码 -> View -> Show Bytecode 或者 cmd 输入 javap -c XXX.class
// 我删除了一些不必要的代码
public class com/Al_tair/generic_/Generic02 
  // 省略始化Generic02类
  public static main([Ljava/lang/String;)V
   L0  //   C<A> C = new C<A>(new A());
    LINENUMBER 9 L0
    NEW com/Al_tair/generic_/C 
    DUP 
    NEW com/Al_tair/generic_/A 
    DUP 
    INVOKESPECIAL com/Al_tair/generic_/A.<init> ()V
    // Ljava/lang/Object; (L开头 内容是对象 ;结尾 ) 传入是Object对象
    // 原本默认传进去就是Object类的对象,使用的时候使用自动强转换成对应传入的类型(现象如下)
    INVOKESPECIAL com/Al_tair/generic_/C.<init> (Ljava/lang/Object;)V 
    ASTORE 1
   L1  //   C<A> C2 = new C<A>(new B());
    LINENUMBER 10 L1
    NEW com/Al_tair/generic_/C
    DUP
    NEW com/Al_tair/generic_/B
    DUP
    INVOKESPECIAL com/Al_tair/generic_/B.<init> ()V
    INVOKESPECIAL com/Al_tair/generic_/C.<init> (Ljava/lang/Object;)V
    ASTORE 2
   L2
    LINENUMBER 11 L2
    RETURN
    GETFIELD com/Al_tair/generic_/C.c : Ljava/lang/Object;
    // 此处有一个checkcast指令,checkcast 用于检查类型强制转换是否可以进行,也就是泛型在获取值的时候进行了强制类型转换。
    CHECKCAST com/Al_tair/generic_/A
   L3
    ......
                            

类型擦除的缺点

1.使用类型擦除直接导致了对于原始的数据类型无法支持,比如int,long这种,因为java不支持Object类型和基本数据类型之间的强制类型转换,也就是说一旦类型擦除之后,就没法在进行 类型转换了。也正是这样,现在的泛型都是不支持原始类型的,比如ArrayList,而不能使用ArrayList。

2.运行期间无法获得泛型类型信息。因为泛型都被擦除了,都被替换成了裸类型。这样就导致了下面的程序都会报错,比如无法使用泛型来创建对象,或者数组。

自定义泛型

自定义泛型类

基本语法

class 类名<泛型>

注意细节

  • 泛型类的类型是在创建对象时确定的(因为创建对象时,需要指定确定的类型)所以在类加载就创建的成员无法使用泛型

    • 普通成员可以使用泛型(属性和方法)但是成员变量不能赋值

    • 静态方法中不能使用类的泛型

    • 使用泛型的数组不能直接初始化 不能初始化的原因

      //  E[] e = new E[3]; 报错
      

自定义泛型接口

基本语法

interface 接口名<泛型>

注意细节

  • 静态成员中不能使用类的泛型
  • 泛型接口的类型是在实现接口的时候确定的
  • 没有指定类型,则默认为Object类型

自定义方法

基本语法

// 一般参数列表和泛型对应
修饰符<泛型>返回类型 方法名(参数列表) 
// 以下非泛型方法,而是使用了泛型
public void XXX(E e)

注意细节

  • 泛型方法可以放在普通类或者泛型类中
  • 方法在使用之前,类型必须确定

泛型的继承和同配符

  • 泛型不具有继承性
  • <?> : 支持任意类型
  • <? extends A> :支持A 类以及A类的子类,规定了泛型的上限
  • <> super A> ;支持A类以及A类的父类,规定了泛型的下限

相关面试题

什么是泛型?泛型的作用?

  • Java 泛型(Generics)是 JDK 5 中引入的一个新特性。
  • 使用泛型参数,可以增强代码的可读性以及稳定性。编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如 ArrayList<Persion> persons = new ArrayList<String>() 这行代码就指明了该ArrayList 对象只能传入 Persion 对象,如果传入其他类型的对象就会报错。
  • 可以用于构建泛型集合。原生 List 返回类型是 Object ,需要手动转换类型才能使用,使用泛型后编译器自动转换。

推荐面试题

以上是关于浅谈java泛型的主要内容,如果未能解决你的问题,请参考以下文章

java泛型中的下限

java 泛型的上限与下限

java泛型上限下限,通配符

java泛型上限下限,通配符

JAVA-初步认识-常用对象API(集合框架-泛型-泛型限定-下限)

JAVA泛型之<? extends T>:(通配符上限)和<? super T>(通配符下限)