Java泛型(generics)是JDK 5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时监测非法的类型。使用泛型机制编写的程序代码要比那些杂乱地使用Object
变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有用,例如,ArrayList就是一个无处不在的集合类。
泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。
如何使用Java泛型
要了解在Java中如何使用泛型,我们可以使用ArrayListJava集合框架的类。
ArrayList类是泛型类的一个示例。我们可以使用ArrayList来存储任何类型的数据。例如
示例
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
//创建一个数组列表来存储Integer 数据
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(4);
list1.add(5);
System.out.println("ArrayList of Integer: " + list1);
//创建数组列表来存储String 数据
ArrayList<String> list2 = new ArrayList<>();
list2.add("Four");
list2.add("Five");
System.out.println("ArrayList of String: " + list2);
//创建数组列表来存储Double 数据
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。 尖括号<>在泛型中称为类型参数。
参数type用于指定泛型类或方法适用的对象(数据)的类型。
创建泛型类
现在我们知道了泛型在Java中的工作方式,让我们看看如何创建自己的泛型类。
示例:创建泛型类
示例
class Main {
public static void main(String[] args) {
//用整数数据初始化泛型类
GenericsClass<Integer> intObj = new GenericsClass<>(5);
System.out.println("泛型类返回: " + intObj.getData());
//用字符串数据初始化泛型类
GenericsClass<String> stringObj = new GenericsClass<>("Java Programming");
System.out.println("泛型类返回: " + stringObj.getData());
}
}
class GenericsClass<T> {
//T型变量
private T data;
public GenericsClass(T data) {
this.data = data;
}
//返回T类型变量的方法
public T getData() {
return this.data;
}
}
输出结果
泛型类返回: 5
泛型类返回: 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) {
//使用Integer数据初始化类
DemoClass demo = new DemoClass();
demo.<String>genericsMethod("Java Programming");
}
}
class DemoClass {
//泛型方法
public <T> void genericsMethod(T data) {
System.out.println("这是一个泛型方法。");
System.out.println("传递给方法的数据是 " + data);
}
}
输出结果
这是一个泛型方法。
传递给方法的数据是: Java Programming
在上面的示例中,我们创建了一个在普通类(DemoClass)内部命名的泛型方法genericsMethod。
public <T> void genericMethod(T data) {...}
在此,将类型参数<T>插入到修饰符(public)之后和返回类型(void)之前。
我们可以通过将实际类型<String>放在方法名前面的括号中来调用泛型方法。
demo.<String>genericMethod("Java Programming");
注意:在大多数情况下,我们可以在调用泛型方法时省略type参数。这是因为编译器可以使用传递给方法的值来匹配类型参数。例如,
demo.genericsMethod("Java Programming");
有界类型
通常,type参数可以接受任何数据类型(原始类型除外)。但是,如果我们只想将泛型用于某些特定类型(例如接受数字类型的数据),则可以使用有界类型。
我们使用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) {
//创建一个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.编译时类型检查
泛型的type参数提供有关泛型代码中使用的数据类型的信息。
因此,可以在编译时识别任何错误,比运行时错误更容易修复。例如,
//不使用泛型
NormalClass list = new NormalClass();
//调用NormalClass的方法
list.display("String");
在上面的代码中,我们有一个普通的类。我们通过传递字符串数据来调用此类的名为display()的方法。
在这里,编译器不知道在参数中传递的值是否正确。但是,让我们看看如果改用泛型类会发生什么。
//使用泛型
GenericsClass<Integer> list = new GenericsClass<>();
//调用GenericsClass的方法
list2.display("String");
在上面的代码中,我们有一个泛型类。 在这里,类型参数表示该类正在处理Integer数据。
因此,当字符串数据在参数中传递时,编译器将生成一个错误。
3.泛型与集合一起使用
集合框架使用Java中的泛型概念。例如,
// 创建一个字符串类型ArrayList
ArrayList<String> list1 = new ArrayList<>();
// 创建一个整数类型ArrayList
ArrayList<Integer> list2 = new ArrayList<>();
在上面的示例中,我们使用了相同的ArrayList类来处理不同类型的数据。
类似ArrayList,其他集合(LinkedList,Queue,Maps,等等)也是Java的泛型。