文章目录
一、 泛型
1 概述
泛型(Generic)是一种编程概念,它是指一种可以用于多种不同的数据类型的程序设计方式。它是一种类或方法,可以接受不同类型的参数,以达到代码复用的目的。
2 核心思想
在 Java、C# 等编程语言中,泛型是一种重要的编程机制,可以适用于各种数据结构,如List、Set、Map等等。泛型的核心思想是参数化类型,即定义类或方法时不指定具体的数据类型,而是使用一个参数来代替数据类型,具体的数据类型在使用时再传递进来。例如,Java中的List接口可以通过泛型来实现一个通用的列表类,同时支持存储各种数据类型的对象。
3 优点
-
泛型使得代码变得更为灵活和复用性更强,可以使用相同的类或方法来处理不同类型的数据,而无需针对不同的数据类型重复编写相似的代码。
-
使用泛型的优点包括增加代码的可读性、减少代码重复、提高代码复用性和可维护性等。
-
把运行时的问题,提到了编译期间
-
泛型也可以大大减少类型转换的使用,从而避免了类型转换错误的发生,并提高代码的性能。
4 格式
Java中泛型的定义格式如下:
class/interface 类型名称<泛型参数列表> {
在此可以使用泛型参数列表中的参数
}
其中,类型名称代表定义的类或接口名称,泛型参数列表用尖括号 < > 括起来,泛型参数之间用逗号隔开。
在类或接口中可以使用泛型参数,以限定方法参数、方法返回值及成员变量的数据类型,例如:
class MyClass<T> {
private T data;
public void setData(T data){
this.data = data;
}
public T getData(){
return data;
}
}
上面的例子中,MyClass 是一个使用泛型的类,T 是泛型参数,可以用于限定 setData() 方法的参数类型和 getData() 方法的返回值类型,也可以用于成员变量 data 的数据类型。
使用泛型的好处是,可以在编译时检查类型安全性,防止类型转换错误的发生,并且代码具有更好的灵活性和可重用性。
二、泛型类
1 概述
泛型类(Generic Class)是一种定义了类型参数的类,它可以适用于不同类型的数据。
2 定义格式
修饰符 class 类名<T>{
// 成员变量和方法
}
其中,T 是类型参数,可以在类中使用,表示一种占位符类型,相当于在定义类时定义了一种类型,可以在该类内使用。常见的如T、E 、K、V等形式的参数常用于表示泛型
泛型类可以使用在任何数据类型上,并且可以用于所有的方法返回类型和参数类型。例如,Java中的List接口、Map接口等都是泛型类。通过泛型,可以灵活地实现多种类型的List和Map,从而提高代码的可重用性和灵活性。
3 举例
下面是一个在Java中的泛型类的例子:
public class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
以上是一个简单的泛型类 Box,它的类型参数是 T。Box 类用于存储一个对象,并提供了一个返回该对象的方法 getValue()。
我们可以使用泛型类 Box 来存储不同类型的对象,例如:
Box<Integer> intBox = new Box<Integer>(10);
Box<String> strBox = new Box<String>("Hello");
上面的代码定义了两个不同的 Box 对象,一个用于存储整型,一个用于存储字符串。在定义时,需要指定 T 的实际类型。可以通过调用 getValue() 方法来获取存储在 Box 对象中的值。由于泛型的作用,这两个Box对象可以在处理数据时实现代码的复用。
三、 泛型方法
1 概述
泛型方法 (Generic Method) 可以独立于泛型类而存在,它可以在普通类中定义,也可以在泛型类中定义。
在 Java 中,泛型方法可在以下位置定义:
- 在泛型类中
- 在非泛型类中
- 接口中
2 格式
一个泛型方法可以定义在一个普通类中,其格式如下:
修饰符 <T, V, ...> 返回类型 方法名 (参数列表) {
方法体
}
其中,泛型参数列表 T、V 等是可变的,方法体中的代码可以使用这些泛型参数。
3 举例
public class MyUtil {
public static <T> void printArray(T[] array) {
for(T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}
上面的代码中,MyUtil 类中定义了一个泛型方法 printArray(),它可以处理任何类型的数组参数,并输出数组的元素值。
在使用泛型方法时,需要显式地指定泛型参数类型。例如:
Integer[] intArray = {1, 2, 3, 4, 5};
MyUtil.<Integer>printArray(intArray);
上面的代码中,我们调用了 MyUtil 类中的 printArray() 泛型方法处理一个整型数组,并显式地指定了泛型参数类型为 Integer。
四、泛型接口
1 概述
泛型接口 (Generic Interface) 是一种定义了类型参数的接口,它和泛型类一样可以适用于不同类型的数据。
2 格式
泛型接口的定义格式为:
interface 接口名<T> {
// 方法和静态常量
}
其中,T 是类型参数,可以在接口内使用,表示一种占位符类型,和泛型类的类型参数类似。
3 场景
- 泛型接口可以和泛型类一样使用在任何数据类型上,并且可以用于所有的方法返回类型和参数类型。
例如,Java中的Map.Entry接口就是一个泛型接口,它定义了一个键值对,其中键和值都可以是不同类型的任何对象类型。 - 泛型接口的使用和泛型类类似,可以通过类型参数来指定具体的数据类型。
- 可以通过在实现时指定不同的类型参数来定义多种类型的接口,提高接口的灵活性。
4 优点
使用泛型接口的好处是和泛型类类似,提高了代码的安全性和灵活性,使得代码更具通用性和可重用性。
5 举例
下面是一个在Java中的泛型接口的例子:
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
以上代码定义了一个泛型接口 Pair,它有两个类型参数 K 和 V,用于表示两个元素的类型。Pair 接口包含了两个方法 getKey() 和 getValue(),用于获取键和值的值。
我们可以在任何类中实现 Pair 接口,例如:
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
上面的代码定义了一个类 OrderedPair,它实现了 Pair 接口,并根据实际需要定义了键和值的类型。在 OrderedPair 类中,我们需要实现 Pair 接口中所有的方法,以保证 OrderedPair 实例能够正确地获取其键和值的值。
通过泛型接口,我们可以灵活地定义不同类型的键值对,而且可以保证类型安全,提高了代码的重用性和可读性。
五、类型通配符
1 概述
在Java泛型中,类型通配符(Wildcard)是一种使用?通配符(?)来表示未知类型的占位符,具体类型在使用时会由编译器根据上下文推断。通过使用类型通配符,我们可以编写更加灵活的泛型代码,使其能够处理多种类型的数据。
2 分类
类型通配符可以用于定义泛型方法、泛型类和泛型接口中的参数、返回值、成员变量和数组。类型通配符主要有以下三种形式:
?
:表示未知的类型参数,它可以匹配任何数据类型;? extends 类型
:表示类型参数是类型的子类型(包括自身),可以用于限制泛型类型的上界,如List<? extends Number>
表示 List 中元素的类型必须是 Number 类型或其子类;? super 类型
:表示类型参数是类型的超类型(包括自身),可以用于限制泛型类型的下界,如List<? super Integer>
表示 List 中元素的类型必须是 Integer 类型或其父类。
3 举例
import java.util.List;
public class MyUtil {
public static double sum(List<?> list) {
double sum = 0;
for (Object obj : list) {
if (obj instanceof Number) {
sum += ((Number) obj).doubleValue();
}
}
return sum;
}
public static void copy(List<? extends Number> src, List<? super Number> dest) {
for (Number num : src) {
dest.add(num);
}
}
}
上面的代码中,使用了 List<?>
和 List<? extends Number>
类型通配符来表示未知的泛型类型和泛型类型的上界。其中 sum()
方法可以计算 List 中所有数值的和,而 copy()
方法可以将一个 List 中的元素复制到另一个 List 中,通过使用类型通配符,这两个方法可以适用于任何数据类型。
六、可变参数
1 概述
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
2 格式
修饰符 返回值类型 方法名(数据类型… 变量名){}
eg: public static int sum(int... a) {}
注意事项:
- 这里的变量a,其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
3 举例
下面举一个Java中,使用泛型可变参数实现数组转换为列表的例子:
import java.util.ArrayList;
import java.util.List;
public class ArrayToList {
public static <T> List<T> arrayToList(T... array) {
List<T> list = new ArrayList<>();
for (T element : array) {
list.add(element);
}
return list;
}
public static void main(String[] args) {
String[] array = {"apple", "banana", "orange"};
List<String> list = arrayToList(array);
System.out.println(list); // 输出:[apple, banana, orange]
}
}
在上面的例子中,我们定义了一个泛型方法 arrayToList
,这个方法使用了可变参数来接收一个数组,并且将数组转换为一个列表。方法的泛型类型为 <T>
。在方法内部,我们通过遍历数组,将数组元素添加到 List 中,最终返回 List 对象。
在 main 方法中,我们声明一个 String 类型的数组,将其传递给 arrayToList 方法,并得到一个 String 类型的 List 对象,然后使用输出语句输出这个 List 对象:[apple, banana, orange]。