1。简介在jdk5.0中引入了Java泛型以减少错误并在类型上添加额外的抽象层。本文将简要介绍Java中的泛型、泛型背后的目标以及如何使用泛型来提高代码质量。2.为什么要使用泛型?想象一个场景,我们想在Java中创建一个列表来存储Integer;代码可以这样写:Listlist=newLinkedList();list.add(newInteger(1));Integeri=list.iterator().next();令人惊讶的是,编译器提示输入最后一行。它不知道返回的数据类型是什么。因此,编译器提示需要显式转换:Integeri=(Integer)list.iterator.next();没有合同保证列表的返回类型是整数。定义的列表可以包含任何对象。我们只知道我们正在通过检查上下文来检索列表。在查看类型时,它只能保证它是一个对象,因此需要显式转换以确保类型是安全的。这种转换可能有噪音,我们知道这个列表中的数据类型是整数。如果它被转换,它也会弄乱我们的代码。如果程序员在显式转换中出错,可能会引发类型相关的运行时错误。如果程序员可以表达他们使用特定类型的意图,并且编译器可以确保该类型的正确性,那就更容易了。这是泛型背后的核心思想。我们将前面代码片段的第一行修改为:Listlist=newLinkedList<>();通过添加包含类型的菱形运算符<>,我们将此列表的特化范围缩小到Integer类型,指定将保存在列表中的类型。编译器可以在编译时强制执行类型。在较小的程序中,这似乎是一个微不足道的添加。但在较大的程序中,这可以显着增加健壮性并使程序更易于阅读。3.泛型方法泛型方法是用单个方法声明编写的方法,可以用不同类型的参数调用。编译器将确保所使用类型的正确性。以下是泛型方法的一些属性:泛型方法在方法声明的返回类型之前有一个类型参数(包装类型的菱形运算符)类型参数可以有界(边界在本文后面解释)泛型方法可以有不同的方法的类型参数在方法签名中以逗号分隔。泛型方法的方法体定义为普通方法。将数组转换为列表的通用方法示例:publicListfromArrayToList(T[]a){returnArrays.stream(a).collect(Collectors.toList());}在前面的示例中,方法声明中的表示该方法将处理泛型类型T。即使该方法返回void,这也是必需的。上面说了,一个方法可以处理多个泛型类型,这种情况下所有的泛型类型都必须添加到方法声明中,比如我们要修改上面的方法来处理类型T和类型G,应该是这样的写入:publicstaticListfromArrayToList(T[]a,FunctionmapperFunction){returnArrays.stream(a).map(mapperFunction).collect(Collectors.toList());}我们正在传递一个函数,该函数将具有类型T元素的数组转换为包含类型G元素的列表。例如,将Integer转换为其String表示形式:@TestpublicvoidgivenArrayOfIntegers_thanListOfStringReturnedOK(){Integer[]intArray={1,2,3,4,5};ListstringList=Generics.fromArrayToList(intArray,Object::toString);assertThat(stringList,hasItems("1","2","3","4","5"));}Oracle建议对泛型类型使用大写字母,选择更具描述性的字母来表示Formal类型,如在Java集合中,T代表类型,K代表键,V代表值。3.1.GenericBounds如前所述,类型参数可以有界。Bounded是“受限”的意思,我们可以限制一个方法可以接受的类型。例如,您可以指定一个方法接受一个类型及其所有子类(上限)或一个类型及其所有超类(下限)。要声明上限类型,我们在类型后使用关键字extends,然后是要使用的上限。例如:publicListfromArrayToList(T[]a){...}这里使用关键字extends表示类型T扩展类的上限,或者实现接口的上限.3.2.多个边界类型也可以有多个上限,如下所示:如果T扩展的类型之一是类(即Number),则它必须放在边界列表的第一位。否则,将导致编译时错误。4.使用通配符通配符用问号“?”表示在Java中,它们用于指代未知类型。通配符在使用泛型时特别有用,可以用作参数类型,但首先要考虑一个重要的注意事项。众所周知,Object是所有Java类的超类型,但是Object的集合并不是任何集合的超类型。(可能有点绕,仔细看)比如List不是List的超类型,将List类型的变量赋值给List类型的变量会导致编译错误。这是为了防止在将异构类型添加到同一集合时可能发生的冲突。相同的规则适用于任何类型及其子类型的集合。看一下这个例子:即使House是Building的子类型。如果您需要将此方法用于Building类型及其所有子类型,则可以按如下方式实现有界通配符:publicstaticvoidpaintAllBuildings(Listbuildings){...}现在,此方法可以处理Building类型和所有子类型。这称为上限通配符,其中类型Building是上限。也可以使用下限指定通配符,其中未知类型必须是指定类型的超类型。可以使用super关键字后跟特定类型来指定下限,例如对于未知类型,它是T的超类型(=T及其所有父类)。5.类型擦除泛型被添加到Java中以确保类型安全并确保泛型不会在运行时造成开销,编译器在编译时对泛型应用称为类型擦除的过程。类型擦除删除所有类型参数并用它们的边界替换它们,如果类型参数是无界的,则用Object替换它们。因此,编译后的字节码只包含普通的类、接口和方法,保证不会产生新的类型。正确的类型转换也适用于编译时的Object类型。下面是一个类型擦除的例子:publicListgenericMethod(Listlist){returnlist.stream().collect(Collectors.toList());}使用类型擦除,无界类型T将是替换为Object如下://forillustrationpublicList