用简洁的语言详细讲解Java泛型;结合简单、清晰的Java代码示例,一看就懂,懂了才不会忘记

在这里插入图片描述

泛型概述

泛型程序设计

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。——《百度百科》

Java泛型

Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型,而且无法直接使用基本值类型作为泛型类型参数。——《百度百科》

使用泛型的好处

  • 编译期进行类型检查,消除运行期ClassCastException异常;
  • 消除了强制类型转换,减少不必要的代码。

泛型类型

在类/接口的定义中含有类型参数,类型参数在整个类/接口中有效。

泛型类(接口)

示例的泛型类中包含一个类型参数T,T可以接收任意引用变量类型。
泛型接口与泛型类相似。

/** 泛型类 */
public class GenericClass<T> {
  private T t;

  public T getT() {
    return t;
  }

  public void setT(T t) {
    this.t = t;
  }

  public static void main(String[] args) {
    GenericClass<String> genericString = new GenericClass<>();
    genericString.setT("a string");
    String resString = genericString.getT();
    System.out.println("泛型<String> , t is : " + resString);
    GenericClass<Integer> genericInteger = new GenericClass<>();
    genericInteger.setT(1);
    // 自动拆箱
    int resInt = genericInteger.getT();
    System.out.println("泛型<Integer> , t is : " + resInt);
  }
}

泛型的命名规范

泛型类型使用单个大写字母命名,比如T。以下列出一些常用的类型参数:

  • E : Element (used extensively by the Java Collections Framework)
  • K : Key
  • N : Number
  • T : Type
  • V : Value
  • S,U,V etc. : 2nd, 3rd, 4th types

多种类型参数

示例的类中含有2个类型参数K,V。

/**
 * 两个类型参数的泛型示例
 *
 * @param <K> key
 * @param <V> value
 */
public class MyMap<K, V> {
  private K k;
  private V v;

  public MyMap(K k, V v) {
    this.k = k;
    this.v = v;
  }

  public V getV(K k) {
    return v;
  }

  public static void main(String[] args) {
    MyMap<String, String> myStringMap = new MyMap<>("key", "value");
    String vString = myStringMap.getV("key");
    System.out.println(vString);
    MyMap<Integer, Integer> myIntMap = new MyMap<>(1, 1);
    // unboxing
    int vInt = myIntMap.getV(1);
    System.out.println(vInt);
  }
}

泛型方法

在方法的定义中含有类型参数,类型参数在整个方法中有效。
静态方法、非静态方法、构造方法中都允许含有类型参数。

/** 在方法中使用泛型 */
public class GenericMethod {
  /**
   * 非静态方法
   *
   * @param t
   * @param <T>
   * @return
   */
  public <T> T nonStaticGet(T t) {
    return t;
  }

  /**
   * 静态方法
   *
   * @param t
   * @param <T>
   * @return
   */
  public static <T> T staticGet(T t) {
    return t;
  }

  /**
   * 多类型参数
   *
   * @param key
   * @param value
   * @param <K>
   * @param <V>
   * @return
   */
  public <K, V> String put(K key, V value) {
    // 存储key、value...
    return "key : " + key + " , value : " + value;
  }

  public static void main(String[] args) {
    String str = GenericMethod.staticGet("static method!");
    System.out.println(str);
    GenericMethod gm = new GenericMethod();
    str = gm.nonStaticGet("non-static method!");
    System.out.println(str);
    str = gm.put(1, "one");
    System.out.println(String.format("Multiple Type Parameters! %s", str));
  }
}

有界类型参数

  • 使用类型参数T时,对传入的参数是没有任何限制;我们可以使用extends关键字实现对类型参数的限制,比如:T extends Number,T只允许传入数字类型的参数;extends关键字后面可以是类或者接口;
  • extends后面可以有多个类型限制,比如:<T extends A & B & C>。注意如果A、B、C中有一个是类,则类必须被放置在第一个位置,如例子中的A。
public class BoundedTypeParameters {
  public static <T extends Number> void print(T t) {
    System.out.println("The number is " + t);
  }

  public <T extends A & B & C> void multipleBounds(T t) {
    /* ... */
  }

  /**
   * 编译出错 —— 类必须在第一个位置
   *
   * @param t
   * @param <T>
   */
  //  public <T extends B & A & C> void multipleBounds1(T t) {}

  public static void main(String[] args) {
    BoundedTypeParameters.print(1);
    BoundedTypeParameters.print(1.1D);
    // 编译错误
    //    BoundedTypeParameters.print("1");
  }

  class A {
    /* ... */
  }

  interface B {
    /* ... */
  }

  interface C {
    /* ... */
  }
}

通配符

通配符表示未知类型,在泛型中用?表示通配符,例如:List<?>。

上界通配符

使用extends关键字,例如<? extends Number>,类型参数只能是Number本身或Number的子类。

下届通配符

使用super关键字,例如<? super Integer>,类型参数只能是Integer本身或Integer的父类。

/** 泛型通配符例子 */
public class Wildcards {
  /**
   * 无界通配符
   *
   * @param list
   */
  public void print(List<?> list) {
    for (Object o : list) {
      System.out.print(o + " ");
    }
    System.out.println();
  }

  public void printUpperBounded(List<? extends Number> list) {
    for (Object o : list) {
      System.out.print(o + " ");
    }
    System.out.println();
  }

  public void printLowerBounded(List<? super Integer> list) {
    for (Object o : list) {
      System.out.print(o + " ");
    }
    System.out.println();
  }

  public static void main(String[] args) {
    Wildcards wildcards = new Wildcards();
    List<Integer> intList = Arrays.asList(1, 2);
    wildcards.print(intList);
    wildcards.printUpperBounded(intList);
    List<String> strList = Arrays.asList("1", "2");
    // 编译出错,类型参数只能是Number本身或Number的子类,如:List<Integer>
    // wildcards.printUpperBounded(strList);
    List<Object> objList = Arrays.asList("Hello", "World!");
    wildcards.printLowerBounded(objList);
    // 编译出错,类型参数只能是Integer本身或Integer的父类,如:List<Object>
    // wildcards.printLowerBounded(strList);
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡矣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值