📜  Java泛型

📅  最后修改于: 2020-09-26 14:41:41             🧑  作者: Mango

在本教程中,我们将通过示例了解Java泛型,如何创建泛型类和方法及其优势。

在Java中, 泛型有助于创建可与不同类型的对象(数据)一起使用的类,接口和方法。因此,允许我们重用我们的代码。

注意泛型不适用于基本类型( intfloatchar等)。


泛型的工作

要了解泛型在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 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 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 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类来存储IntegerStringDouble类型的元素。由于Java泛型,这是可能的。

在这里,请注意这行,

ArrayList list1 = new ArrayList<>();

我们在尖括号<>使用了Integer 。尖括号<>在泛型中称为类型参数

type参数用于指定泛型类或方法适用的对象(数据)的类型。


创建泛型类

现在我们知道了泛型在Java中的工作方式,让我们看看如何创建自己的泛型类。

示例:创建泛型类

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

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

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

class GenericsClass {

  // 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表示类型参数 。主类中,我们已经创建了一个名为intObj的stringObj GenericsClass的对象。

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

创建泛型方法

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

示例:创建通用方法

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

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

class DemoClass {

  // generics method
  public  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  void genericMethod(T data) {...}

在此,将类型参数插入到修饰符( public )之后和返回类型( void )之前。

我们可以通过将实际类型放在方法名称之前的方括号内来调用泛型方法。

demo.genericMethod("Java Programming");

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

demo.genericsMethod("Java Programming");

有界类型

通常, type参数可以接受任何数据类型(原始类型除外)。但是,如果我们只想将泛型用于某些特定类型(例如接受数字类型的数据),则可以使用有界类型。

我们使用extends关键字。例如,


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

示例:有界类型

class GenericsClass  {

  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 obj = new GenericsClass<>();
  }
}

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

 

这意味着T只能使用属于Number子代的数据类型( IntegerDouble等等)。

但是,我们使用String创建了泛型类的对象。这就是为什么当我们运行程序时,会出现以下错误。

GenericsClass 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

Java泛型的优点

1.代码可重用性

泛型使我们能够编写适用于不同类型数据的代码。例如,

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

在这里,我们创建了一个泛型方法。此方法可用于对整数数据, 字符串数据等执行操作。

2.编译时类型检查

泛型的type参数提供有关泛型代码中使用的数据类型的信息。

因此,可以在编译时识别任何错误,比运行时错误更容易修复。例如,

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

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

在上面的代码中,我们有一个普通的类。我们通过传递字符串数据来调用此类的名为display()的方法。

在这里,编译器不知道在参数中传递的值是否正确。但是,让我们看看如果使用泛型类会发生什么。

// using Generics
GenericsClass 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 list1 = new ArrayList<>();

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

在上面的示例中,我们使用了相同的ArrayList类来处理不同类型的数据。

ArrayList相似,其他集合( LinkedListQueueMaps等)在Java中也是通用的。