在本教程中,我们将通过示例了解 Java 泛型,如何创建泛型类和方法及其优势。
在 Java 中,泛型帮助创建可与不同类型的对象(数据)一起使用的类,接口和方法。 因此,允许我们重用我们的代码。
注意:泛型不适用于基本类型(int
,float
,char
等)。
泛型的工作原理
要了解 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
。 尖括号<>
在泛型中称为类型参数。
类型参数用于指定泛型类或方法适用的对象(数据)的类型。
创建泛型类
现在我们知道了泛型在 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
Generic Class returns: 5
Generic Class returns: Java Programing
在上面的示例中,我们创建了一个名为GenericsClass
的泛型类。 此类可用于处理任何类型的数据。
class GenericsClass<T> {...}
在此,T
表示类型参数。 在Main
类内部,我们创建了名为intObj
和stringObj
的GenericsClass
对象。
- 在创建
intObj
时,类型参数T
被Integer
代替。 这意味着intObj
使用GenericsClass
处理整数数据。 - 在创建
stringObj
时,类型参数T
被替换为String
。 这意味着stringObj
使用GenericsClass
处理字符串数据。
创建泛型方法
与泛型类相似,我们也可以使用 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");
有界类型
通常,类型参数可以接受任何数据类型(原始类型除外)。 但是,如果我们只想将泛型用于某些特定类型(例如接受数字类型的数据),则可以使用有界类型。
我们使用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
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");
在上面的代码中,我们有一个泛型类。 在这里,类型参数指示该类正在处理Integer
数据。
因此,当在参数中传递字符串数据时,编译器将生成错误。
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 中也是通用的。