美文网首页
JAVA泛型

JAVA泛型

作者: 独自闯天涯的码农 | 来源:发表于2022-03-29 14:14 被阅读0次

    一、泛型简介

    1、目的

    • 语法糖:
      也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
      Java中最常用的语法糖主要有泛型、变长参数、条件编译、自动拆装箱、内部类等。
      服拟机并不支持这些语法,它们在编译阶段就被还原回了简单的基础语法结构,这个过程成为解语法糖。
    • 泛型的目的:
      Java 泛型就是把一种语法糖,通过泛型使得在编译阶段完成一些类型转换的工作,避免在运行时强制类型转换而出现 ClassCastException,即类型转换异常。

    • 泛型的作用:
      可以把类型参数看作是使用参数化类型时指定的类型的一个占位符。

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

    2、泛型的好处

    1. 类型安全。类型错误现在在编译期问就被捕获到了,而不是在运行时当作
      java.lang. Class CastException展示出来,将类型检查从运行时挪到编译时有助于开
      发者更容易找到错误,并提高程序的可靠性。
    2. 消除了代码中许多的强制类型转换,增强了代码的可读性。
    3. 为较大的优化带来了可能。

    二、泛型的使用

    1、泛型类和泛型接口

    1/定义接口时指定了一个类型形参,该形参名为E
    public interface List<E> extends Collection<E>{
      //在该接口里,E可以作为类型使用
      public E get (int index) {}
      public void add(E e) {}
    }
    
    1/定义类时指定了一个类型形参,该形参名为E
    public class ArrayList<E> extends AbstractList<E> implements List<E> {
    //在该类里,E可以作为类型使用
      public void set(E e) {
      -------
      }
    }
    

    这就是泛型的实质:允许在定义接口、类时声明类型形参,类型形参在整个接口、类体内可当成类型使用,几乎所有可使用普通类型的地方都可以使用这种类型形参

    • 泛型类
      定义一个容器类,存放键值对key-value,键值对的类型不确定,可以使用泛型来定义,分别指定为K和V。
    public class Container<K, V> {
      private K key;
      private V value;
    
      public Container (K k, V V) {
        key = k;
        value= V;
      }
      public K getkey) {
        return key;
      }
      public V getValue() {
        return value;
      }
      public void setKey() {
        this. key = key;
      }
      public void setvalue) {
        this. value = value;
      }
    }
    

    JDK1.7增加了泛型的“菱形"语法:Java允许在构造器后不需要带完成的泛型信息,只要给出一对尖括号(<>)即可,Java可以推断尖括号里应该是什么泛型信息;List<String> list = new ArrayList<>();

    • 泛型类派生子类
      当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或者从该父类派生子类,需要注意:使用这些接口、父类派生子类时不能再包含类型形参,需要传入具体的类型。

    2、泛型方法

    所谓泛型方法,就是在声明方法时定义一个或多个类型形参。泛型方法的用法格式如下:

    修饰符 <T,S> 返回值类型 方法名(形参列表){
      方法体
    }
    

    注意:方法声明中定义的形参只能在该方法里使用,而接口、类声明中定义的类型形参则可以在整个接口、类中使用。

    public <T> T fun(T t){
      return t;
    }
    

    3、泛型构造器

    正如泛型方法允许在方法签名中声明类型形参一样,Java也允许在构造器签名中声明类型形参,这样就产生了所谓的泛型构造器。
    和使用普通泛型方法一样没区别,一种是显式指定泛型参数,另一种是隐式推断;如果是显式指定则以显式指定的类型参数为准,如果传入的参数的类型和指定的类型实参不符,将会编译报错。

    //隐式
    new Person(22);
    //显示
    new<String> Person("Hello");
    

    三、类型通配符

    类型通配符:顾名思义就是匹配任意类型的类型实参;

    类型通配符是一个问号(?),将一个问号作为类型实参传给List集合,写
    作:List<?>(意恩是元素类型未知的List)。这个问号(?)被成为通配符,它
    的元素类型可以匹配任何类型。

    1、带限通配符

    1. 上限通配符
      如果想限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends 关键字指定这个类型必须是继承某个类,或者实现某个接口,也可以是这个类或接口本身。
    它表示集合中的所有元素都是Shape 类型或者其子类。
    List<? extends Shape>
    
    1. 下限通配符
      如果想限制使用泛型类别时,只能用某个特定类型或者是其父类型才能实例化该类型时,可以在定义类型时,使用super关键字指定这个类型必须是是某个类的父类,或者是某个接口的父接口,也可以是这个类或接口本身。
    它表示集合中的所有元素都是Circle类型或者其父类。
    List<? super Circle>
    

    注意:
    extends 可用于的返回类型限定,不能用于参数类型限定。
    super 可用于参数类型限定,不能用于返回类型限定。
    List<? extends Fruit> list = new ArrayList<Apple>();
    不能使用list.add方法添加元素;
    List<? super Fruit> flist = new ArrayList<Fruit>();
    不能使用list.get方法获取元素;

    2、类型擦除

    Class c1=new ArrayList<Integer>().getclass();
    Class c2=new ArrayList<String>().getclass();
    System.out.println(c1==c2);
    这个值为true
    

    这是因为不管为泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一类处理,在内存中也只占用一块内存空间。从Java泛型这一概念提出的目的来看,其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
    在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。

    相关文章

      网友评论

          本文标题:JAVA泛型

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