你好啊!在本文中,我们将了解JavaGenerics、如何创建泛型类和方法、它的优点以及如何使用它们来提高代码的质量。
JavaGenerics是在JDK5.0中引入的,目的是减少bug,并在类型上增加一个额外的抽象层。泛型指参数化类型。JavaGenerics允许我们创建一个单独的类、接口和方法,这些类、接口和方法可以用于不同类型的数据(对象),这有助于我们重用代码。
泛型方法是用单个方法声明编写的方法,可以用不同类型的参数调用。
泛型还提供编译时类型安全,允许程序员在编译时捕获无效类型。
“重要的是要注意,Generics不适用于原语类型(int、Float、char等)。”
为什么是泛型?
假设我们想要在Java中创建一个列表来存储Integer;我们可以尝试编写:
List list = new LinkedList();
list.add(new Integer(1));
Integer i = list.iterator().next();
编译器会抱怨最后一行,因为它不知道返回什么数据类型,它需要显式的转换:
Integer i = (Integer) list.iterator.next();
现在,这个转换可能很烦人,我们知道这个列表中的数据类型是一个Integer。我们的代码也杂乱无章。如果程序员在显式转换中出错,则会导致与类型相关的运行时错误。
如果程序员能够表达他们使用特定类型的意图,并且编译器能够确保这种类型的正确性,那就容易多了。这是仿制药背后的主要想法。
现在让我们修改代码。
List<Integer> list = new LinkedList<>();
通过添加包含类型的操作符<>,我们将这个列表的专门化缩小到Integer类型,也就是说,我们指定将在列表中保存的类型。然后,编译器可以在编译时强制执行该类型。这可以增加显着的健壮性,并使程序更容易阅读。
我们可以创建一个可以与任何类型的数据一起使用的类。这种类称为泛型类。下面是如何在Java中创建泛型类:
class Main {
public static void main(String[] args) {
GenericsClass<Integer> intObj = new GenericsClass<>(5);
System.out.println("Generic Class returns: " + intObj.getData());
GenericsClass<String> stringObj = new GenericsClass<>("Java Programming");
System.out.println("Generic Class returns: " + stringObj.getData());
}
}
class GenericsClass<T> {
private T data;
public GenericsClass(T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
输出
Generic Class returns: 5
Generic Class returns: Java Programming
在这里,我们创建了一个名为GenericsClass的泛型类,这个类可以用于处理任何类型的数据。
class GenericsClass<T> {...}
这里,角括号内使用的T<>表示类型参数。在主类中,我们创建了GenericsClass的两个对象
IntObj-在这里,类型参数T被Integer替换。现在,GenericsClass处理整数数据。
String Obj-在这里,类型参数T被字符串替换。现在,GenericsClass处理字符串数据。
我们还可以创建一个可以与任何类型的数据一起使用的方法。这类被称为泛型方法。
下面是如何在Java中创建泛型类:
class Main {
public static void main(String[] args) {
DemoClass demo = new DemoClass();
demo.<String>genericsMethod("Java Programming");
demo.<Integer>genericsMethod(25);
}
}
class DemoClass {
public <T> void genericsMethod(T data) {
System.out.println("Generics Method:");
System.out.println("Data Passed: " + data);
}
}
输出
Generics Method:
Data Passed: Java Programming
Generics Method:
Data Passed: 25
因此,在上面的代码中,我们创建了一个名为genericsMethod的泛型方法。
public <T> void genericMethod(T data) {...}
我们可以通过将实际类型和括号中的实际类型放在方法名称之前来调用泛型方法。
demo.<String>genericMethod("Java Programming");
demo.<Integer>genericMethod(25);
我们可以在不包含类型参数的情况下调用泛型方法。例如,
demo.genericsMethod("Java Programming");
有界类型
让我们来看看有界类型。Type参数可以接受任何数据类型(基本类型除外)。
有界的意思是“受限”,我们可以限制可以被方法接受的类型。
如果我们只想对某些特定类型使用泛型(例如接受数字类型的数据或接受字符串类型的数据),那么我们可以使用有界类型。
在绑定类型的情况下,我们使用EXTEND关键字。
<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<String> obj = new GenericsClass<>();
}
}
在上面的代码中,我们创建了一个名为GenericsClass的类。注意,GenericsClass表达式是用有界类型创建的。这意味着GenericsClass只能处理属于数字子类(Integer、Double等)的数据类型。
泛型优势
它促进代码重用:在Java泛型的帮助下,我们可以编写处理不同类型数据的代码。
public <T> void genericsMethod(T data) {...}
以上方法可用于对整数数据、字符串数据等执行操作。
类型安全
在编译时了解代码中的问题总是比让代码在运行时失败更好
泛型在出现编译时会出现错误,而不是在运行时出现错误。
GenericsClass<Integer> list = new GenericsClass<>();
在这里,我们知道GenericsClass只使用Integer数据。
如果我们尝试将Integer以外的数据传递给这个类,程序将在编译时生成一个错误。
不需要单独铸造
import java.util.*;
class Test
{
public static void main(String[] args)
{
ArrayList <String> al = new ArrayList<String> ();
al.add("Success");
al.add("Gideon");
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);
}
}
如果我们不使用泛型,那么,在上面的示例中,每次我们从ArrayList检索数据时,都必须将其键入类型。实际上,在每次检索操作中进行类型转换都会带来很大的压力。如果我们已经知道我们的列表只包含字符串数据,那么我们不需要每次都输入它。
import java.util.*;
class Test
{
public static void main(String[] args)
{
ArrayList <String> al = new ArrayList<String> ();
al.add("Success");
al.add("Gideon");
String s1 = al.get(0);
String s2 = al.get(1);
}
}
结语
泛型是Java语言的一个强大的补充,因为它使程序员的工作更容易,并且不太容易出错。泛型在编译时执行类型正确性,并且它支持实现泛型算法,而不会给我们的应用程序带来额外的开销。
|