当前位置:   article > 正文

Java中的泛型介绍_java泛型

java泛型

Java中的泛型介绍

概述

Java 泛型(generics)是 JDK 5 中引入的, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

泛型的好处是

在编译的时候检查类型安全;

避免了强制类型转换运行时异常;

同一个类可以操作多种类型数据,提高代码复用。

Java 中泛型标记符

在 Java 中,泛型标记符用于表示类型参数。下面是一些常用的泛型标记符及其含义:

  1. E:代表元素(Element)类型,通常在集合中使用,如 List<E>。
  2. K:代表键(Key)的类型,通常在 Map 中使用,如 Map<K, V>。
  3. V:代表值(Value)的类型,通常在 Map 中使用,如 Map<K, V>。
  4. T:代表任意类型(Type),通常在方法中使用,如 public <T> T method(T obj)。
  5. N:代表数字类型,如 Number 类型。
  6. R:代表返回类型,如 public <T> R method(T obj)。

这些泛型标记符只是一种约定,并没有强制规定必须使用它们,你可以使用任何可以作为标识符的字符来表示类型参数。但是,为了代码的可读性和可维护性,建议使用这些标记符。

为什么使用泛型?

如果要实现不同类型的加法,每种类型都需要重载一个add方法。使用泛型适用于多种数据类型执行相同的代码,示例源码如下:

  1. public class NeedGeneric1 {
  2. private static int add(int a, int b) {
  3. System.out.println(a + "+" + b + "=" + (a + b));
  4. return a + b;
  5. }
  6. private static float add(float a, float b) {
  7. System.out.println(a + "+" + b + "=" + (a + b));
  8. return a + b;
  9. }
  10. private static double add(double a, double b) {
  11. System.out.println(a + "+" + b + "=" + (a + b));
  12. return a + b;
  13. }
  14. //使用泛型
  15. private static <T extends Number> double add(T a, T b) {
  16. System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
  17. return a.doubleValue() + b.doubleValue();
  18. }
  19. public static void main(String[] args) {
  20. NeedGeneric1.add(1, 2); //1+2=3
  21. NeedGeneric1.add(1f, 2f); //1.0+2.0=3.0
  22. NeedGeneric1.add(1d, 2d); //1.0+2.0=3.0
  23. NeedGeneric1.add(Integer.valueOf(1), Integer.valueOf(2)); //1+2=3.0
  24. NeedGeneric1.add(Float.valueOf(1), Float.valueOf(2)); //1.0+2.0=3.0
  25. NeedGeneric1.add(Double.valueOf(1), Double.valueOf(2)); //1.0+2.0=3.0
  26. }
  27. }

Java泛型的应用

下面举几个例子来说明Java泛型的应用。

1.泛型类

定义一个泛型类:public class GenericClass<T>{},例如:

  1. //泛型类例子
  2. public class GenericClass<T> {
  3. private T data;
  4. public T getData() {
  5. return data;
  6. }
  7. public void setData(T data) {
  8. this.data = data;
  9. }
  10. public static void main(String[] args) {
  11. GenericClass<String> genericClass=new GenericClass<>();
  12. genericClass.setData("Generic Class");
  13. System.out.println(genericClass.getData()); //Generic Class
  14. }
  15. }

2.泛型方法

定义一个泛型方法: private static<T> TgenericAdd(T a, T b) {},例如:

  1. //泛型方法例子
  2. public class GenericMethod1 {
  3. private static int add(int a, int b) {
  4. System.out.println(a + "+" + b + "=" + (a + b));
  5. return a + b;
  6. }
  7. private static <T> T genericAdd(T a, T b) {
  8. System.out.println(a + "+" + b + "="+a+b);
  9. return a;
  10. }
  11. public static void main(String[] args) {
  12. GenericMethod1.add(1, 2); //1+2=3
  13. GenericMethod1.<String>genericAdd("a", "b"); //a+b=ab
  14. }
  15. }

3.泛型接口

定义一个泛型接口文件:public interface GenericIntercace<T>{},例如:

  1. //定义一个泛型接口文件
  2. public interface GenericIntercace<T> {
  3. T getData();
  4. }

泛型接口分两种实现方法:

一是实现类不明确泛型接口的类型参数变量,这时实现类也必须定义类型参数变量;

二是明确泛型接口的类型参数变量。

实现泛型接口方式一,不明确泛型接口的类型参数变量:public class ImplGenericInterface1<T> implements GenericIntercace<T>,例如:

  1. //泛型接口方式一,不指定具体类型实现方式
  2. public class ImplGenericInterface1<T> implements GenericIntercace<T> {
  3. private T data;
  4. private void setData(T data) {
  5. this.data = data;
  6. }
  7. @Override
  8. public T getData() {
  9. return data;
  10. }
  11. public static void main(String[] args) {
  12. ImplGenericInterface1<String> implGenericInterface1 = new ImplGenericInterface1<>();
  13. implGenericInterface1.setData("Generic Interface1");
  14. System.out.println(implGenericInterface1.getData()); //Generic Interface1
  15. }
  16. }

实现泛型接口方式二,明确泛型接口的类型参数变量:public class ImplGenericInterface2 implements GenericIntercace<String> {},例如:

  1. //泛型接口方式二,指定具体类型实现方式
  2. public class ImplGenericInterface2 implements GenericIntercace<String> {
  3. @Override
  4. public String getData() {
  5. return "Generic Interface2";
  6. }
  7. public static void main(String[] args) {
  8. ImplGenericInterface2 implGenericInterface2 = new ImplGenericInterface2();
  9. System.out.println(implGenericInterface2.getData()); //Generic Interface2
  10. }
  11. }

4.泛型通配符

Java中的泛型通配符是指 "?" 符号,表示一个未知类型的通配符。它可以用作方法参数、方法返回值和类中的成员变量等地方。

extends关键字设定上行边界,即指明参数类型的顶层类,限定实例化泛型类时传入的具体类型,只能是继承自顶层类的。

super关键字设置下行边界,即指定参数类型的底层类,限定传入的参数类型只能是设定类的父类。

通配符有以下三种使用方式:

<? extends T> 表示类型上界,表示类型必须是T或T的子类。

<? super T> 表示类型下界,表示类型必须是T或T的父类。

<?> 表示无限制通配符,表示可以是任意类型。

使用通配符可以使代码更加灵活,特别是在涉及到多态性和继承关系时。但需要注意,对于带有通配符的泛型类型,不能对其中的元素进行添加操作,只能进行读取操作。

下面给出 Java 泛型通配符示例

★以下是一个使用<? extends T>泛型通配符的示例代码

  1. //<? extends T>通配符示例
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class ExampleA {
  5. public static void main(String[] args) {
  6. List<? extends Number> list = new ArrayList<>();
  7. List<Integer> intList = new ArrayList<>();
  8. intList.add(1);
  9. intList.add(2);
  10. List<Double> doubleList = new ArrayList<>();
  11. doubleList.add(1.0);
  12. doubleList.add(2.0);
  13. // 下面两行都会编译报错,
  14. // 因为在声明时使用了 <? extends Number> 上界并不能允许添加元素。
  15. // list.add(3);
  16. // list.add(3.0);
  17. // 可以读取列表的元素,读取操作是允许的。
  18. int sum = 0;
  19. for (Number n : intList) {
  20. //System.out.println(n);
  21. sum += n.intValue();
  22. }
  23. System.out.println("sum: " + sum);//sum: 3
  24. double sumB = 0;
  25. for (Number n : doubleList) {
  26. //System.out.println(n);
  27. sumB += n.doubleValue();
  28. }
  29. System.out.println("sum: " + sumB);//sum: 3.0
  30. }
  31. }

在这个例子中,我们声明了一个 List<? extends Number> 类型的列表 list,它表示一个包含 Number 类型或其子类类型的列表。尽管 list 是一个列表类型的变量,但是我们不能向其添加任何元素,因为 <? extends Number> 上界限制了可以添加到列表中的元素类型。我们可以安全地从 list 中读取元素,并且这些元素都是 Number 类型或其子类类型。

★以下是一个使用<? super T>泛型通配符的示例代码:

  1. //<? super T>通配符示例
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class ExampleB {
  5. public static void main(String[] args) {
  6. List<Number> numbers = new ArrayList<>();
  7. numbers.add(1);
  8. numbers.add(2.0);
  9. List<? super Integer> integers = numbers;
  10. integers.add(3);
  11. System.out.println(integers); // 输出 [1, 2.0, 3]
  12. }
  13. }

这个示例中,我们首先创建了一个List<Number>对象,并向其中添加了两个元素:整数1和浮点数2.0。然后,我们将这个列表赋值给一个通配符类型的变量integers,该变量声明为<? super Integer>,表示它可以接受所有Integer的超类型(包括Integer本身)。最后,我们向integers列表中添加了一个整数3,这是完全合法的,因为Integer是Number的子类型。输出结果为[1, 2.0, 3]。

★以下是一个使用<? >泛型通配符的示例

例1、代码:

  1. //<?>通配符示例
  2. import java.util.*;
  3. public class ExampleC {
  4. public static void printList(List<?> list) {
  5. for (Object elem : list)
  6. System.out.print(elem + " ");
  7. System.out.println();
  8. }
  9. public static void main(String[] args) {
  10. List<Integer> intList = Arrays.asList(1, 2, 3);
  11. List<String> strList = Arrays.asList("one", "two", "three");
  12. printList(intList); //1 2 3
  13. printList(strList); //one two three
  14. }
  15. }

在此示例中,我们定义了一个名为“printList”的静态方法,它接受一个未知类型的List作为参数,并打印每个元素。然后,我们创建一个Integer类型的List和一个String类型的List,并将它们分别传递给printList方法。由于该方法的参数类型是通配符,它可以接受任何类型的List,因此这两个列表都可以成功打印其元素。

例2、再给出一个<?>泛型通配符示例代码:

  1. //又一个<?>泛型通配符示例
  2. public class Example<T> {
  3. private T value;
  4. public void setValue(T value) {
  5. this.value = value;
  6. }
  7. public T getValue() {
  8. return value;
  9. }
  10. public static void printValue(Example <?> example) {
  11. System.out.println(example.getValue());
  12. }
  13. public static void main(String[] args) {
  14. Example<Integer> intExample = new Example<Integer>();
  15. intExample.setValue(10);
  16. printValue(intExample); //10
  17. Example<String> stringExample = new Example<String>();
  18. stringExample.setValue("Hello, world!");
  19. printValue(stringExample); //Hello, world!
  20. }
  21. }

在上面的示例中,printValue 方法的参数类型为 Example <?>,这表示可以接受任何类型的 Example 实例,但是我们无法知道它的具体类型。这个通配符 ? 限制了我们对其进行操作的能力,但是仍然可以打印出值。

Java泛型类型可以继承或实现其他泛型类型或非泛型类型,但遵循以下规则:

泛型类型不能直接继承非泛型类型。

子类中的泛型类型可以比父类中的泛型类型具体化(即指定更具体的类型),但不能泛化(即使用更广泛的类型)。

当使用泛型类作为参数时,如果子类中的泛型类型比父类中的泛型类型具体化,则可以传递子类对象作为参数;反之则不行。

使用通配符(?)可以传递任意类型的泛型对象作为参数,但无法在方法中使用该泛型类型(因为我们无法确定其具体类型)。

总之,泛型类型之间的继承关系必须满足类型匹配的规则。

附录

Java 泛型详解https://www.cnblogs.com/coprince/p/8603492.html

Java 中的泛型 https://blog.csdn.net/weixin_45395059/article/details/126006369

官方介绍

Lesson: Generics https://docs.oracle.com/javase/tutorial/extra/generics/

Generics (Updated) https://docs.oracle.com/javase/tutorial/java/generics/index.html

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号