了解Java泛型

    在本教程中,我们将通过示例了解Java泛型,如何创建泛型类和方法及其优势。
    在Java中,泛型帮助创建可用于不同类型对象(数据)的类、接口和方法。因此,允许我们重用代码。
    注意:泛型不适用于基本类型(int、float、char等)。

1. 泛型的作用

    为了理解Java中如何使用泛型,我们可以使用Java集合框架的ArrayList类。
    ArrayList类是一个泛型类的例子。我们可以使用ArrayList存储任何类型的数据。例如,

import java.util.ArrayList;

class Main {
    
    
   public static void main(String[] args) {
    
    

      // create an array list to store Integer data
      ArrayList<Integer> list1 = new ArrayList<>();
      list1.add(4);
      list1.add(5);
      System.out.println("ArrayList of Integer: " + list1);

      // creates an array list to store String data
      ArrayList<String> list2 = new ArrayList<>();
      list2.add("Four");
      list2.add("Five");
      System.out.println("ArrayList of String: " + list2);

      // creates an array list to store Double data
      ArrayList<Double> list3 = new ArrayList<>();
      list3.add(4.5);
      list3.add(6.5);
      System.out.println("ArrayList of Double: " + list3);
   }
}

    输出:

ArrayList of Integer: [4, 5]
ArrayList of String: [Four, Five]
ArrayList of Double:  [4.5, 6.5]

    在上面的例子中,我们使用了相同的ArrayList类来存储Integer、String和Double类型的元素。由于存在Java泛型,这是可能的。
    在这里,请注意这行,

ArrayList<Integer> list1 = new ArrayList<>();

    我们在尖括号内使用了Integer。尖括号<>在泛型中被称为类型参数。
    类型参数用于指定泛型类或方法所处理的对象(数据)的类型。

2. 创建泛型类

    既然我们知道了泛型在Java中是如何工作的,那么让我们看看如何创建自己的泛型类。

示例:创建泛型类
class Main {
    
    
  public static void main(String[] args) {
    
    

    // initialize generic class with Integer data
    GenericsClass<Integer> intObj = new GenericsClass<>(5);
    System.out.println("Generic Class returns: " + intObj.getData());

    // initialize generic class with String data
    GenericsClass<String> stringObj = new GenericsClass<>("Java Programming");
    System.out.println("Generic Class returns: " + stringObj.getData());
  }
}

class GenericsClass<T> {
    
    

  // variable of T type
  private T data;

  public GenericsClass(T data) {
    
    
    this.data = data;
  }

  // method that return T type variable
  public T getData() {
    
    
    return this.data;
  }
}

    输出:

Generic Class returns: 5
Generic Class returns: Java Programing

    在上面的示例中,我们创建了一个名为 GenericsClass 的泛型类。此类可用于处理任何类型的数据。

class GenericsClass<T> {
    
    ...}

    这里,T表示类型参数。在Main类中,我们创建了GenericsClass的对象intObj和stringObj。

  • 在创建intObj时,类型参数T被Integer替换。这意味着intObj使用GenericsClass处理整数数据。
  • 在创建stringObj时,类型参数T被String替换。这意味着stringObj使用GenericsClass处理字符串数据。

3. 创建泛型方法

    与泛型类相似,我们也可以使用Java创建自己的泛型方法。

示例:创建通用方法
class Main {
    
    
  public static void main(String[] args) {
    
    

    // initialize the class with Integer data
    DemoClass demo = new DemoClass();
    demo.<String>genericsMethod("Java Programming");
  }
}

class DemoClass {
    
    

  // generics method
  public <T> void genericsMethod(T data) {
    
    
    System.out.println("This is a generics method.");
    System.out.println("The data passed to method is " + data);
  }
}

    输出:

This is a generics method.
The data passed to the method: Java Programming

    在上面的示例中,我们在一个普通类中创建了一个名为genericsMethod的泛型方法。

public <T> void genericMethod(T data) {
    
    ...}

    这里,将类型参数<T>插入到修饰符(public)之后和返回类型(void)之前。
    我们可以通过将实际类型<String>放在方法名前面的括号内来调用泛型方法。

demo.<String>genericMethod("Java Programming");

    注意:在大多数情况下,我们可以在调用泛型方法时省略类型参数。这是因为编译器可以使用传递给方法的值来匹配类型参数。例如,

demo.genericsMethod("Java Programming");

4. 有界类型

    一般来说,类型参数可以接受任何数据类型(基本类型除外)。但是,如果我们只想对某些特定类型使用泛型(例如接受数字类型的数据),那么我们可以使用有界类型。
    我们使用extends关键字。例如,

<T extends A>

    这意味着T只能接受属于A子类型的数据。

示例:有界类型
class GenericsClass <T extends Number> {
    
    

  public void display() {
    
    
    System.out.println("This is a bounded type generics class.");
  }
}

class Main {
    
    
  public static void main(String[] args) {
    
    

    // create an object of GenericsClass
    GenericsClass<String> obj = new GenericsClass<>();
  }
}

    在上面的示例中,我们创建了一个有界类型的泛型类。在这里,请注意表达式,

<T extends Number>

    这意味着 T 只能使用Number(Integer,Double等等)子级的数据类型。
    但是,我们已经创建了一个String的泛型类对象。这就是为什么当我们运行程序时,我们会得到以下错误。

GenericsClass<String> obj = new GenericsClass<>();
                                                 ^
    reason: inference variable T has incompatible bounds
      equality constraints: String
      lower bounds: Number
  where T is a type-variable:
    T extends Number declared in class GenericsClass

5. Java泛型的优点

    1.代码可重用性
    泛型允许我们编写可与不同类型的数据一起使用的代码。例如,

public <T> void genericsMethod(T data) {
    
    ...}

    在这里,我们创建了一个泛型方法。此方法可用于对整数数据,字符串数据等执行操作。
    2.编译时类型检查
    泛型的类型参数提供有关泛型代码中使用的数据类型的信息。
    因此,可以在编译时识别任何错误,比运行时错误更容易修复。例如,

// without using Generics
NormalClass list = new NormalClass();

// calls method of NormalClass
list.display("String");

    在上面的代码中,我们有一个普通的类。我们通过传递字符串数据来调用此类的名为display()的方法。
    在这里,编译器不知道在参数中传递的值是否正确。但是,让我们看看如果改用泛型类会发生什么。

// using Generics
GenericsClass<Integer> list = new GenericsClass<>();

// calls method of GenericsClass
list2.display("String");

In the above code, we have a generics class. Here, the type parameter indicates that the class is working on Integer data.

Hence when the string data is passed in argument, the compiler will generate an error.

    3.用于集合
    集合框架使用Java中的泛型概念。例如,

// creating a string type ArrayList
ArrayList<String> list1 = new ArrayList<>();

// creating a integer type ArrayList
ArrayList<Integer> list2 = new ArrayList<>();

    在上面的示例中,我们使用了相同的ArrayList类来处理不同类型的数据。
    类似ArrayList,其他集合(LinkedList,Queue,Maps,等等)也是Java的泛型。

参考文档

[1]Parewa Labs Pvt. Ltd.Java Generics[EB/OL].https://www.programiz.com/java-programming/generics,2020-01-01.
[2]w3cschool编程狮.Java 泛型类[EB/OL].https://www.w3cschool.cn/java/java-generic-classes.html,2018-01-19.

猜你喜欢

转载自blog.csdn.net/zsx0728/article/details/109447387
今日推荐