Java泛型是一项强大的编程特性,为程序员提供了一种灵活、类型安全、可重用的编码方式。通过泛型,我们能够编写更加通用、适应多种数据类型的代码,从而提高了代码的灵活性和可维护性。在这篇博客中,我们将深入探讨Java泛型的各个方面,并通过具体的例子来展示其用法和优势。
1. 泛型类和泛型方法
在以下代码中,printArray
方法使用了泛型类型参数 T
,允许我们在运行时指定具体的类型。这种方式使得我们可以编写通用的方法来处理不同类型的数组。
public class Print {/*** 打印数组* @param inputArray* @param <T>*/public static <T> void printArray(T[] inputArray) {for (T element : inputArray) {System.out.printf("%s ", element);}System.out.println();}/*** 打印整数数组* @param inputArray*/public static void IntPrintArray(Integer[] inputArray) {for (Integer element : inputArray) {System.out.printf("%s ", element);}System.out.println();}/*** 打印字符串数组* @param inputArray*/public static void StrPrintArray(String[] inputArray) {for (String element : inputArray) {System.out.printf("%s ", element);}System.out.println();}
}
然后,我们通过一个示例程序 Method01
来展示泛型方法的应用:
/*** @ClassName: Method01* @Description: 方法1 感受泛型的好处,泛型方法* @Author: liu* @Date: 2024-03-09* @Version: 1.0**/
public class Method01 {public static void main(String[] args) {String[] stringArray = {"Hello", "World"};Integer[] integerArray = {1, 2, 3, 4, 5};System.out.println("字符串数组包含:");//StringPrint方法Print.StrPrintArray(stringArray);//编译失败 类型不一致//Print.StrPrintArray(integerArray);//泛型方法Print.printArray(stringArray);System.out.println("\n整数数组包含:");//IntegerPrint方法Print.IntPrintArray(integerArray);//编译失败 类型不一致//Print.IntPrintArray(stringArray);//泛型方法,提高代码可用性Print.printArray(integerArray);System.out.println("\n整数数组包含:");Object[] objectArray = {1, 2, 3, 4, 5, "Hello", "World"};Print.printArray(objectArray);}
}
在上述示例中,我们调用了 printArray
方法,分别传递了字符串数组和整数数组。由于泛型的存在,我们能够使用相同的方法处理不同类型的数据,提高了代码的可重用性。
再举个例子
/*** @ClassName: Method03* @Description: 方法3 可以存储任意类型的数据* @Author: liu* @Date: 2024-03-09* @Version: 1.0**/
public class Method3 {public static void main(String[] args) {// 创建一个存储整数的 Box 实例Box<Integer> integerBox = new Box<>();integerBox.setValue(42);System.out.println("Integer Value: " + integerBox.getValue());// 创建一个存储字符串的 Box 实例Box<String> stringBox = new Box<>();stringBox.setValue("Hello, Generics!");System.out.println("String Value: " + stringBox.getValue());// 创建一个存储布尔值的 Box 实例Box<Boolean> booleanBox = new Box<>();booleanBox.setValue(true);System.out.println("Boolean Value: " + booleanBox.getValue());}
}
@Data
class Box<T> {private T value;
}
2. 泛型上限和下限通配符
首先,让我们来看一个简单的泛型类和泛型方法的例子。考虑到动物(Animals
)和猫(Cat
)、狗(Dog
)的实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Animals {public String name;public Integer age;
}@Data
public class Cat {public String name;public Integer age;public Say say;public Cat(String name, Integer age, Say say) {this.name = name;this.age = age;this.say = say;System.out.println("Cat的全参构造执行,猫边唱歌吃鱼");}public Cat() {System.out.println("Cat的无参构造执行,你创建了猫,却一笑而过!");}
}@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dog extends Animals {public String name;public Integer age;
}@Data
public class Say {public String say;public Say(String say) {this.say = say;System.out.println("说话" + say);}
}
接下来,我们将介绍泛型上限和下限通配符的概念,并通过例子 Method02
进行演示。
/*** @ClassName: Method02* @Description: 方法2, 泛型上限和下限通配符* @Author: liu* @Date: 2024-03-09* @Version: 1.0**/
public class Method02 {public static void main(String[] args) {
/* Cat cat = new Cat();Dog dog1 = new Dog("旺财", 3);Cat cat1 = new Cat("小花", 2, new Say("喵喵喵"));Animals animal1 = new Animals("小动物", 1);List<Dog> dogList = new ArrayList<>();List<Cat> catList = new ArrayList<>();List<Animals> animalsList = new ArrayList<>();animalsList.add(animal1);dogList.add(dog1);catList.add(cat1);*/// 使用菱形操作符和双括号初始化简化代码// 在匿名内部类中,Java 并不允许使用 <> 进行菱形操作符的类型推断,还可以使用 Arrays.asList() 方法List<Dog> dogList = new ArrayList<Dog>(){private static final long serialVersionUID = -3322276720822396481L;{add(new Dog("狗王", 2));add(new Dog("狗王后", 3));}};List<Cat> catList = Arrays.asList(new Cat("猫王", 1, new Say("喵~")),new Cat());List<Animals> animalsList = new ArrayList<Animals>(){private static final long serialVersionUID = 1L;{add(new Animals("小动物", 1));}};//reason: no instance(s) of type variable(s) exist so that Cat conforms to Animals//extendMethod(catList);// 编译报错// 泛型方法调用示例extendMethod(dogList); // 合法,List<Dog> 是 List<? extends Animals> 的子类extendMethod(animalsList); // 合法,List<Animals> 是 List<? extends Animals> 的子类System.out.println("=====================================");superMethod(dogList); // 合法//编译报错,List<Cat> 不是 List<? super Dog> 的子类//superMethod(catList);//编译合法,运行报错UnsupportedOperationException//superMethod(Collections.unmodifiableList(catList));superMethod(animalsList); // 合法}public static <T extends Animals> void extendMethod(List<T> list) {// 在这里处理只包含数字类型及其子类的列表for (T element : list) {System.out.println(element);}}public static void superMethod(List<? super Dog> list) {// 在这里处理只包含数字类型及其父类的列表list.add(new Dog("二狗", 2));//list.add(new Animals("Buddy", 2)); // 编译报错for (Object element : list) {System.out.println(element);}}
}
在上述代码中,extendMethod
方法接受一个泛型列表,其中的元素必须是 Animals
类型或其子类。而 superMethod
方法则接受一个泛型列表,其中的元素必须是 Dog
类型或其父类。这样的灵活性使得我们能够对不同层次的类进行处理。
在 Method02
的示例程序中,我们演示了泛型上限和下限通配符的使用:
在这个示例中,我们展示了如何使用泛型上限和下限通配符来处理不同类型的列表,使得我们的代码更具通用性和灵活性。
3. 灵活处理多个泛型参数
在实际的编程场景中,有时我们需要处理多个泛型参数的情况。在这个章节,将探讨如何在Java中灵活地处理多个泛型参数,以满足更为复杂的编码需求。
代码如下:
/*** @ClassName: Method04* @Description: 演示带有多个泛型参数的Pair类的使用* @Author: 阿水* @Date: 2024-03-10* @Version: 1.0**/
public class Method04 {public static void main(String[] args) {// 创建一个带有泛型参数的Pair实例Pair<Dog, Cat> pair = new Pair<>();// 创建狗和猫的实例Dog dog = new Dog("旺财", 3);Cat cat = new Cat("小花", 2, new Say("喵喵喵"));// 设置Pair实例的值pair.setFirst(dog);pair.setSecond(cat);// 打印Pair实例的字符串表示形式以及其中的元素System.out.println(pair);System.out.println("First Element: " + pair.getFirst().getName());System.out.println("Second Element: " + pair.getSecond().getName());// 创建带有不同泛型参数的两个Pair实例Pair<String, Integer> pair1 = new Pair<>("One", 1);Pair<Double, String> pair2 = new Pair<>(6.66, "Pi");// 调用泛型方法打印Pair实例的值printPair(pair1);printPair(pair2);}/*** 打印带有泛型参数的Pair实例的值** @param pair 带有泛型参数的Pair实例* @param <T> 第一个元素的类型* @param <U> 第二个元素的类型*/public static <T, U> void printPair(Pair<T, U> pair) {System.out.println("Pair: " + pair.getFirst() + ", " + pair.getSecond());}
}/*** @ClassName: Pair* @Description: 带有两个泛型参数的Pair类* @Author: 阿水* @Date: 2024-03-10* @Version: 1.0**/
@Data
@AllArgsConstructor
@NoArgsConstructor
class Pair<T, U> {private T first;private U second;
}
运行结果如下:
4.总结
Java泛型是一项强大的编程特性,通过泛型类和泛型方法,我们能够编写通用、灵活的代码。同时,泛型上限和下限通配符使得我们能够更好地处理不同层次的类。通过这篇博客,我们深入理解了Java泛型的灵活性、安全性和可重用性,为我们的编程工作提供了更多的便利和可能性。