当前位置: 首页 / 技术分享 / 正文
泛型类和泛型对象

2022-12-29

   泛型 类型

  泛型类就是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。只有用户使用该类的时候,该类所属的类型才能明确。

  泛型类的声明格式具体如下:

  [访问权限] class 类名称<泛型类型标识1, 泛型类型标识2, ..., 泛型类型标识n> {

  [访问权限] 泛型类型标识 变量名称;

  [访问权限] 泛型类型标识 方法名称(参数){};

  [访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称){};

  }

  定义好泛型类之后,就可以创建泛型对象。创建泛型对象的语法格式具体如下:

  类名称<参数化类型> 对象名称 = new 类名称<参数化类型>();

  为了大家更好地理解泛型类以及泛型对象的使用,下面先看一个例子。

  import java.util.ArrayList;

  public class Example22 {

  public static void main(String[] args) {

  ArrayList list = new ArrayList(); // 创建ArrayList集合

  list.add("abc"); // 添加字符串对象

  list.add(10); // 添加Integer对象

  list.add(20);

  for (Object obj : list) { // 遍历集合

  String str = (String) obj; // 强制转换成String类型

  }

  }

  }

  在上述代码中,向List集合存入了3个元素,分别是一个字符串和两个int类型的整数。在取出这些元素时,都将它们强转为String类型,由于Integer对象无法转换为String类型,因此程序在运行时会出现java.lang.ClassCastException的异常。

  接下来,对上述代码进行修改,如下所示:

  ArrayListlist = new ArrayList();

  上面这种写法就限定了ArrayList集合只能存储Integer类型元素,改写后的程序在中编译时就会出现错误提示。修改之后的程序编译报错的原因是修改后的代码限定了集合元素的数据类型,ArrayList这样的集合只能存储Integer类型的元素,程序在编译时,编译器检查出String类型的元素与List集合的规定类型不匹配,编译不通过。

  使用泛型可以很好的解决上述问题。接下来,使用泛型再次对上述案例进行改写。

  import java.util.ArrayList;

  public class Example23 {

  public static void main(String[] args) {

  ArrayListlist = new ArrayList(); // 创建ArrayList集合

  list.add(10); // 添加Integer对象

  list.add(20);

  for (Integer ele : list) { // 遍历集合

  System.out.println(ele);

  }

  }

  }

  上述代码从运行结果可以看出,该文件已经可以正常运行。需要注意的是,在使用泛型后,每次遍历集合元素时,可以指定元素类型为Integer,而不是Object,这样就避免了在程序中进行强制类型转换。

  6.3 泛型方法

  泛型方法的定义与其所在的类是否是泛型类是没有任何关系的,泛型方法所在的类可以是泛型类,也可以不是泛型类。定义泛型方法代码如下所示:

  [访问权限] <泛型标识> 返回值类型 方法名称(泛型标识 参数名称) {}

  接下来通过一个案例来学习泛型方法的定义与使用。

  class Dog {

  String eat;

  Integer age;

  publicvoid show(T t) {

  System.out.println(t);

  }

  }

  public class Example24 {

  public static void main(String[] args) {

  Dog dog = new Dog(); // 创建对象

  //调用方法,传入的参数是什么类型,返回值就是什么类型

  dog.show("hello");

  dog.show(12);

  dog.show(12.5);

  }

  }

  上述代码中,定义了一个泛型方法show(),并将show()方法的参数类型和返回值类型规定为泛型,这样调用方法时,传入的参数是什么类型,返回值就是什么类型,如果定义为其他类型,传入参数就必须是方法指定的参数类型,否则编译就会出现错误。

  6.4 泛型接口

  在JDK5之后,不仅可以声明泛型类,也可以声明泛型接口,声明泛型接口和声明泛型类的语法类似,也是在接口名称后面加上,声明泛型接口的格式如下所示。

  [访问权限] interface 接口名称<泛型标识> {}

  利用以上格式定义一个泛型接口,如下所示。

  interface MyInter{

  T getVar();

  }

  泛型接口定义完成之后,就要定义此接口的子类,定义泛型接口的子类有两种方式,一种是直接在子类实现的接口中明确地给出泛型类型,另一种是直接在子类后声明泛型。

  6.4.1 直接在接口中指定具体类型

  当子类明确泛型类的类型参数变量时,外界使用子类的时候,需要传递类型参数变量进来,在实现类中需要定义出类型参数变量。接下来通过一个案例学习这种情况的泛型接口定义。

  1.首先定义一个泛型接口。

  public interface MyInter{

  void show(T t);

  }

  2.接着定义泛型接口的子类。

  Java

  public class MyInnerImpl implements MyInter{

  @Override

  public void show(String s) {

  System.out.println(s);

  }

  }

  3.最后定义实现类,进行测试。

  public class Example25 {

  public static void main(String[] args) {

  MyIntermyInter = new MyInnerImpl();

  myInter.show("Hello World");

  }

  }

  上述代码中定义了一个泛型接口MyInter,在泛型接口子类MyInterImpl中实现了MyInter接口。MyInterImpl实现MyInter接口时,直接在实现的接口处指定了具体的泛型类型String,这样在重写MyInter接口中的show()方法时直接指明类型为String即可。

  6.4.2 在子类的定义上声明泛型类型

  当子类不明确泛型类的类型参数变量,外界使用子类的时候,也需要传递类型参数变量进来,在实现类中也需要定义出类型参数变量。接下来通过修改子类MyInnerImpl和测试程序来学习这种情况的泛型接口定义。

  1.泛型接口子类MyInnerImpl的实现如下。

  public class MyInnerImplimplements MyInter{

  @Override

  public void show(T t) {

  System.out.println(t);

  }

  }

  2.在Example25类中测试代码实现如下。

  public class Example25 {

  public static void main(String[] args) {

  // ...

  MyIntermyInt = new MyInnerImpl<>();

  myInt.show(20);

  }

  }

  对比上述案例可知,当子类不确定泛型类的类型参数变量时,在定义对象时泛型可以为任意类型。

  6.5 类型通配符

  在Java中,数组是可以协变的,例如,Dog extends Animal,那么Animal[]与dog[]是可以兼容的。而集合是不能协变的,也就是说List不是List的父类, 为了解决这个问题,Java泛型为我们提供了类型通配符“?”。

  下面我们通过一个案例演示通配符的使用。

  import java.util.ArrayList;

  import java.util.List;

  public class Example26 {

  public static void main(String[] args) {

  // List集合装载的是Integer

  Listlist = new ArrayList<>();

  list.add(1);

  list.add(2);

  list.add(3);

  test(list);

  }

  public static void test(List list) {

  for(int i = 0; i<list.size(); p="" {<="" i++)="">

  System.out.println(list.get(i));

  }

  }

  }

  需要注意的是,如果使用通配符“?”接收泛型对象,则通配符“?”修饰的对象只能接收,不能修改,也就是不能设置。下述代码编译时编译器会报错。

  import java.util.ArrayList;

  import java.util.List;

  public class Example27 {

  public static void main(String[] args) {

  List list = new ArrayList();

  list.add("张三");

  // list.add(null);

  }

  }

  由于以上程序将一个字符串设置给泛型所声明的属性,因为使用List的形式,所以无法将内容添加到集合中,但可以设置为null值。因此编译上述代码,编译器会报错,错误描述见下。

  java: 不兼容的类型: java.lang.String无法转换为capture#1, 共 ?

  通配符表示可以匹配任意类型,任意的Java类都可以匹配,但是当接收一个List集合时,它只能操作数字类型的元素(Float、Integer、Double、Byte等数字类型都行),而如果直接使用通配符的话,该集合就不是只能操作数字了。针对这类问题我们可以设定通配符的上限和下限。

  设定通配符上限代码如下所示:

List<? extends Number>

  设定通配符下限代码如下所示:

<? super Type> 

分享: 更多

上一篇:泛型概述

下一篇:JDK8新特性-Lambda表达式

好程序员公众号

  • · 剖析行业发展趋势
  • · 汇聚企业项目源码

好程序员开班动态

More+
  • HTML5大前端 <高端班>

    开班时间:2021-04-12(深圳)

    开班盛况

    开班时间:2021-05-17(北京)

    开班盛况
  • 大数据+人工智能 <高端班>

    开班时间:2021-03-22(杭州)

    开班盛况

    开班时间:2021-04-26(北京)

    开班盛况
  • JavaEE分布式开发 <高端班>

    开班时间:2021-05-10(北京)

    开班盛况

    开班时间:2021-02-22(北京)

    开班盛况
  • Python人工智能+数据分析 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2020-09-21(上海)

    开班盛况
  • 云计算开发 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2019-07-22(北京)

    开班盛况
在线咨询
试听
入学教程
立即报名

Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号