全文共2352字,预计学习时长12分钟
图源:unsplash
作为Java中关键概念,大多数Java代码库都会使用泛型,开发人员在某个时候遇到它们也是不可避免的。正确理解泛型对于掌握Java至关重要,这也会对你的面试有所助益。
本文是关于Java中泛型知识的大放送,泛型是什么,如何在Java中使用,以及它们的优点有哪些,你都能在下文中找到答案。
在Java 5中添加泛型是为了提供编译时类型检查,并消除使用集合类时常见的 ClassCastException 风险。Java中的集合类用于存储和操作对象组。例如,ArrayList集合类可以存储任何类型的对象。因为它被设计成Java基类类型对象的容器。
因此,ArrayList对象可以保存字符串、整数或任何Java类型。在泛型之前,只创建字符串或整数的ArrayList是不可行的。使用泛型定义ArrayList可以容纳的对象类型,因此允许创建单个的ArrayList对象类型:
import java.util.ArrayList;
publicclassGenEx1{
publicstaticvoidmain(String []args){
ArrayList al =newArrayList();
al.add("Name");
al.add("Age");
al.add(22); // Compile Error!
}
}
如上例,泛型类型是通过使用尖括号定义的。在本例中,只有String对象可以存储在ArrayList中。Java中的集合类现在具有泛型类型。接下来,让我们来看看如何编写自己的泛型类、接口和方法。
在泛型类声明中,类的名称后面是类型参数部分。可以使用相同的语法来创建通用接口。类型参数,也称为类型变量,是用于指定泛型类型名称的标识符。泛型类的类型参数部分可以包括一个或多个用逗号分隔的类型参数,这些类也称为参数化类。
classTest{
private K key;
private V value;
Test(K key, V value){
this.key = key;
this.value = value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
}
publicclassGenEx2{
publicstaticvoidmain(String []args){
Test pair1 =newTest("ID",223);
Test pair2 =newTest("Age",22);
System.out.println(pair1.getKey() +"="+ pair1.getValue() );
System.out.println(pair2.getKey() +"="+ pair2.getValue() );
}
}
在上例中,测试类有两个名为K和 v的类型参数,因此测试类的对象可以存储两种不同类型的值。
如果可以编写一个排序方法来对整数数组、字符串数组或任何支持排序的类型的数组中的元素进行排序,该有多好?
图源:unsplash
Java泛型方法允许用一个方法声明指定一组相关类型。这样能够编写单个泛型方法声明,该声明可以用不同类型的参数调用。类型参数部分必须在方法返回类型之前指定,类型参数也可以用作方法的返回类型。
publicclassGenEx3{
publicstatic< E >voidprintArray( E[] inputArray ) {
for(E element : inputArray) {
System.out.print(element +" ");
}
System.out.println();
}
publicstaticvoidmain(String args[]){
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'P', 'I', 'Z', 'Z', 'A' };
System.out.print("integerArray contains: ");
printArray(intArray);
System.out.print("doubleArray contains: ");
printArray(doubleArray);
System.out.print("characterArray contains: ");
printArray(charArray);
}
}
在上例中, printArray 方法可以用来打印任何类型数组的元素。
到目前为止,我们只看到了无界泛型类型参数。无界意味着泛型类型参数可以是我们想要的任何类型,有时可能需要限制允许传递给类型参数的类型。例如,对数字进行操作的方法可能只想接受Number类或其子类的实例,为此使用了有界类型参数。
若要声明有界类型参数,要列出类型参数的名称,后跟extends关键字,然后是它的上界。
publicabstractclassCage {
abstractvoidaddAnimal(T animal)
}
classAnimal{}
classDogextendsAnimal{}
classCatextendsAnimal{}
在本例中,Cage类的泛型类型必须始终是Animal或Animal类的一个子类。因此,我们可以将Cat、Dog或Animal类作为泛型类型参数传递。如果需要,还可以为泛型类型声明多个界限。上面示例中的抽象类可以按照如下所示进行修改:
public abstract class Cage>
在这里,类型参数现在必须同时考虑Animal类和Comparable接口。
问号(?)是泛型中的通配符,表示未知类型。如果希望泛型方法处理所有类型,在本例中可以使用无界通配符。无界通配符由>表示,还可以使用绑定通配符。有界通配符有两种类型,上界通配符和下界通配符。
图源:unsplash
上界通配符用于放宽对方法中变量类型的限制。例如,假设不知道list是数字、整数还是Double类型。那么如何得到列表中所有元素的和呢?可以使用上界通配符来解决这个问题:
publicvoid method( List extends Number> list){
double sum =0;
for(Number i : list){
sum += i.doubleValue();
}
System.out.println(sum);
}
下界通配符用于增加对方法中变量类型的限制。假设只想向一个列表中添加整数,同时又想接受一个Integer超类型的列表。可以使用一个下界通配符来实现这一点:
publicvoid addIntegers(List super Integer> list){
list.add(new Integer(10));
list.add(new Integer(20));
}
虽然 Integer 是Java中 Number 的子类型,但是 List
ArrayList extends Integer> intList =newArrayList<>();
ArrayList extends Number> numList = intList; // OK
ArrayList intList2 =newArrayList<>();
ArrayList numList2 = intList2; // Compile Error!
diamond操作符,也称为diamond语法,是作为Java 7中的一个新特性引入的。diamond操作符的目的是在创建对象时简化泛型的使用。
ArrayList al = newArrayList<>();
通过使用diamond操作符,可以简化字符串ArrayList的声明。
讲过如何使用泛型之后,让我们来探讨一下,我们为何要使用泛型呢?使用泛型有三个主要原因:
· 类型安全
· 不需要类型转换
· 可重用代码
泛型确保了编译时的安全性,这允许在编译代码时捕获无效类型。因此,不需要担心运行时异常。不需要单独的类型转换是使用泛型的另一个优点。定义初始类型,然后让代码进行转换。
图源:unsplash
还可以避免代码重复。如果没有泛型,必须针对不同的类型复制和粘贴相同的代码。使用泛型可以不需要这样做。
好啦,关于Java中泛型的知识都在这里了,要好好掌握呀!
一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”
(添加小编微信:dxsxbb,加入读者圈,一起讨论最新鲜的人工智能科技哦~)