ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Java 泛型 > 原文: [https://www.programiz.com/java-programming/generics](https://www.programiz.com/java-programming/generics) #### 在本教程中,我们将通过示例了解 Java 泛型,如何创建泛型类和方法及其优势。 在 Java 中,**泛型**帮助创建可与不同类型的对象(数据)一起使用的类,接口和方法。 因此,允许我们重用我们的代码。 **注意**:**泛型**不适用于基本类型(`int`,`float`,`char`等)。 * * * ## 泛型的工作原理 要了解 Java 中如何使用**泛型**,我们可以使用 Java 集合框架的`ArrayList`类。 `ArrayList`类是泛型类的示例。 我们可以使用`ArrayList`存储任何类型的数据。 例如, ```java 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); } } ``` 输出量 ```java ArrayList of Integer: [4, 5] ArrayList of String: [Four, Five] ArrayList of Double: [4.5, 6.5] ``` 在上面的示例中,我们使用了相同的`ArrayList`类来存储`Integer`,`String`和`Double`类型的元素。 由于 **Java 泛型**的缘故,这是可能的。 在这里,请注意这行, ```java ArrayList<Integer> list1 = new ArrayList<>(); ``` 我们在尖括号`<>`中使用了`Integer`。 尖括号`<>`在泛型中称为**类型参数**。 类型参数用于指定泛型类或方法适用的对象(数据)的类型。 * * * ## 创建泛型类 现在我们知道了泛型在 Java 中的工作方式,让我们看看如何创建自己的泛型类。 ### 示例:创建泛型类 ```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; } } ``` Output ```java Generic Class returns: 5 Generic Class returns: Java Programing ``` 在上面的示例中,我们创建了一个名为`GenericsClass`的泛型类。 此类可用于处理任何类型的数据。 ```java class GenericsClass<T> {...} ``` 在此,`T`表示**类型参数**。 在`Main`类内部,我们创建了名为`intObj`和`stringObj`的`GenericsClass`对象。 * 在创建`intObj`时,类型参数`T`被`Integer`代替。 这意味着`intObj`使用`GenericsClass`处理整数数据。 * 在创建`stringObj`时,类型参数`T`被替换为`String`。 这意味着`stringObj`使用`GenericsClass`处理字符串数据。 * * * ## 创建泛型方法 与泛型类相似,我们也可以使用 Java 创建自己的泛型方法。 ### 示例:创建泛型方法 ```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); } } ``` **输出** ```java This is a generics method. The data passed to the method: Java Programming ``` 在上面的示例中,我们在普通类内部创建了一个名为`genericsMethod`的泛型方法。 ```java public <T> void genericMethod(T data) {...} ``` 在此,将类型参数`<T>`插入到修饰符(`public`)之后和返回类型(`void`)之前。 我们可以通过将实际类型`<String>`放在方法名称之前的方括号内来调用泛型方法。 ```java demo.<String>genericMethod("Java Programming"); ``` **注意**:在大多数情况下,我们可以在调用泛型方法时省略类型参数。 这是因为编译器可以使用传递给方法的值来匹配类型参数。 例如, ```java demo.genericsMethod("Java Programming"); ``` * * * ## 有界类型 通常,**类型参数**可以接受任何数据类型(原始类型除外)。 但是,如果我们只想将泛型用于某些特定类型(例如接受数字类型的数据),则可以使用有界类型。 我们使用`extends`关键字。 例如, ```java <T extends A> ``` 这意味着`T`只能接受属于`A`子类型的数据。 ### 示例:有界类型 ```java 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<>(); } } ``` 在上面的示例中,我们创建了具有**有界类型**的泛型类。 在这里,请注意表达式 ```java <T extends Number> ``` 这意味着`T`只能使用属于`Number`子级的数据类型(`Integer`,`Double`等)。 但是,我们使用`String`创建了泛型类的对象。 这就是为什么当我们运行程序时,会出现以下错误。 ```java 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 ``` * * * ## Java 泛型的优点 ### 1.代码可重用性 **泛型**允许我们编写适用于不同类型数据的代码。 例如, ```java public <T> void genericsMethod(T data) {...} ``` 在这里,我们创建了一个泛型方法。 此方法可用于对整数数据,字符串数据等执行操作。 ### 2.编译时类型检查 泛型的**类型参数**提供有关泛型代码中使用的数据类型的信息。 因此,可以在编译时识别任何错误,比运行时错误更容易修复。 例如, ```java // without using Generics NormalClass list = new NormalClass(); // calls method of NormalClass list.display("String"); ``` 在上面的代码中,我们有一个普通的类。 我们通过传递字符串数据来调用此类的名为`display()`的方法。 在这里,编译器不知道在参数中传递的值是否正确。 但是,让我们看看如果改用泛型类会发生什么。 ```java // using Generics GenericsClass<Integer> list = new GenericsClass<>(); // calls method of GenericsClass list2.display("String"); ``` 在上面的代码中,我们有一个泛型类。 在这里,类型参数指示该类正在处理`Integer`数据。 因此,当在参数中传递字符串数据时,编译器将生成错误。 ### 3.与集合一起使用 集合框架使用 Java 中泛型的概念。 例如, ```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 中也是通用的。