引言
当我们编写代码时,可能会遇到需要处理不同类型的数据的情况。在传统的编程中,你需要为每种类型编写不同的代码来处理数据,这样会导致代码的重复和冗余。为了解决这个问题,Java 1.5引入了泛型(Generics)的概念。
什么是泛型?泛型是一种编程范式,允许在创建类、接口和方法时使用类型参数。这些类型参数在实际使用时被指定为具体的数据类型,从而实现通用性。通过使用泛型,你可以编写通用的代码,能够处理多种类型的数据,而无需重复编写相似的代码。
泛型的优点有以下几个方面:
- 类型安全:泛型能够在编译期间对类型进行检查,可以避免一些类型转换错误和运行时异常。
- 重用代码:通过泛型,可以编写通用的代码,适用于多种类型的数据,提高代码的重用性。
- 简化代码:使用泛型可以减少冗余代码的编写,使代码更加简洁和易读。
泛型的定义格式如下:
-
<类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如: <E> <T>。
-
<类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>
在java中,泛型主要通过泛型类、泛型方法、泛型接口和通配符等几种方式使用,接下来,本文将详细介绍这几种方式。
泛型类
泛型类是一种具有参数化类型的类,在定义时使用了一个或多个类型参数,多个类型参数之间需要用逗号隔开。这些类型参数可以在实例化泛型类时指定为具体的数据类型,使得该类可以适用于各种不同的数据类型,从而提高了代码的通用性和灵活性。
泛型类的定义格式:修饰符 class 类名<类型> { }。
下面来举一个具体的例子:
1.声明泛型类
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
在上面的例子中,Box
是一个泛型类,<T>
表示这是一个类型参数,它允许在类内部使用这个未知的类型 T
。
2.实例化泛型类
Box<Integer> integerBox = new Box<>();
integerBox.setValue(10);
System.out.println("Value: " + integerBox.getValue()); // 输出: Value: 10
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
System.out.println("Value: " + stringBox.getValue()); // 输出: Value: Hello
在实例化泛型类时,通过 <>
括号内指定具体的数据类型,例如 Box<Integer>
表示使用Integer类型实例化泛型类 Box
。
注意:
类型擦除:Java 中的泛型在编译时会进行类型擦除,泛型信息在运行时被擦除。例如,无法在运行时获取泛型的实际类型参数。
静态上下文中的类型参数:静态方法或静态变量无法直接引用泛型类中定义的类型参数,因为在静态上下文中类型参数尚未确定。
泛型类不能使用基本数据类型作为类型参数,只能使用引用类型。但可以使用对应的包装类(如Integer替代int)。
泛型方法
泛型方法是一个具有类型参数的方法,它可以在方法的定义中使用类型参数,以表示可以处理多种类型的数据。通过使用泛型方法,我们可以编写通用的代码,能够适用于多种类型的数据,而无需为每种类型编写不同的方法。
泛型方法的定义格式:修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
下面是一个使用泛型方法的例子:
public class Generic {
public <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
}
在上面的示例中,我们定义了一个printArray 泛型方法,它接受一个类型为T[]的数组作为参数,并遍历输出数组元素。在方法的定义中使用了类型参数T,以表示该方法可以处理多种类型的数组。
使用泛型方法时,需要在方法调用时指定类型参数的具体类型。例如:
Generic myMethod = new Generic();
Integer[] intArray = {1, 2, 3, 4, 5};
myMethod.printArray(intArray);
String[] stringArray = {"Hello", "World"};
myMethod.printArray(stringArray);
在上面的示例中,我们创建了一个Generic对象,并分别使用 printArray
泛型方法输出了一个整型数组和一个字符串数组的元素。
通过使用泛型方法,我们能够编写通用的代码,提高代码的重用性和灵活性。泛型方法是 Java 中非常有用的特性,在实际开发中经常会遇到,能够简化代码并提高代码的可读性和维护性。
泛型接口
泛型接口是一个具有类型参数的接口,它可以在接口的定义中使用类型参数,以表示可以操作多种类型的数据。通过使用泛型接口,我们可以编写通用的代码,能够适用于多种类型的数据,而无需为每种类型编写不同的接口。
泛型接口的定义格式:修饰符 interface 接口名<类型> { }
下面是一个使用泛型接口的例子:
public interface Generic<T> {
void show(T t);
}
在上面的示例中,我们定义了一个 Generic 泛型接口,它有一个类型参数 T
。该接口有一个show抽象方法。
泛型接口的实现类有两种:
实现类1:定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
例:
public class GenericImpl1<T> implements Generic<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
实现类2:定义实现类时,直接明确泛型的具体类型
例:
public class GenericImpl2 implements Generic<Integer>{
@Override
public void show(Integer t) {
System.out.println(t);
}
}
类型通配符
类型通配符是一种在泛型代码中使用的特殊符号,用于表示未知的类型。它可以用于方法参数、方法返回值以及泛型类中的字段等位置,以增加代码的灵活性和重用性。
在 Java 中,类型通配符使用问号 ?
表示。它可以被用于以下三种形式:
-
类型通配符: <?>
-
ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
-
但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
-
-
类型通配符上限: <? extends 类型>
-
ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型
-
-
类型通配符下限: <? super 类型>
-
ArrayListList <? super Number>: 它表示的类型是Number或者其父类型
-
使用类型通配符的主要目的是在泛型代码中提供更大的灵活性。它允许我们编写适用于多种类型的代码,而不需要具体指定类型参数。
以下是一些使用类型通配符的示例:
public void processList(List<?> list) {
// 对列表进行处理
}
public void addNumbers(List<? extends Number> list) {
// 向列表中添加数字
}
public void printElements(List<? super Integer> list) {
// 打印列表元素
}
在上面的示例中,processList
方法接受一个未知类型的列表作为参数,在方法内部可以对列表进行处理。addNumbers
方法接受一个元素类型为 Number
或其子类的列表,并向列表中添加数字。printElements
方法接受一个元素类型为 Integer
或其父类的列表,并打印列表元素。
通过使用类型通配符,我们可以编写更加通用和灵活的泛型代码,提高代码的重用性和可读性。它是 Java 泛型特性中非常有用的一部分,能够帮助我们处理多种类型的数据。
好了,今天的内容就到处为止,学习java是一个漫长的过程,大家加油!路漫漫其修远兮,吾将上下而求索。