2022最新Java泛型详解(360度无死角介绍)

2022最新Java泛型详解(360度无死角介绍)

什么是Java泛型?

Java泛型是Java SE 5.0版本中的新特性,提供了一种对类型进行参数化的机制,让代码的重用性和类型安全性都得到了极大的提高。

泛型主要有以下特点:

  • 提高代码的可读性和可维护性
  • 在编译期进行类型检查,提高代码的安全性
  • 可以适用于各种类型,提高代码的重用性

如何使用Java泛型?

Java泛型主要包括以下几种用法:

  • 泛型类:使用泛型来定义类
  • 泛型接口:使用泛型来定义接口
  • 泛型方法:使用泛型来定义方法
  • 泛型边界:限定泛型类型的范围

泛型类

public class MyGenericClass<T> {
    private T data;

    public MyGenericClass(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }
}

上面的代码中,MyGenericClass 是一个泛型类,用 T 来表示类型参数。在类的实例化时,可以指定具体类型,例如:

MyGenericClass<String> stringGeneric = new MyGenericClass<>("hello world");
String data = stringGeneric.getData(); // 返回值类型为String

泛型接口

public interface MyGenericInterface<T> {
    T processData(T input);
}

上面的代码中,MyGenericInterface 是一个泛型接口,用 T 来表示类型参数。实现该接口时,需要指定具体类型,例如:

public class MyGenericImpl implements MyGenericInterface<String> {
    @Override
    public String processData(String input) {
        return input.toUpperCase();
    }
}

MyGenericImpl impl = new MyGenericImpl();
String result = impl.processData("hello world"); // 返回值为"HELLO WORLD"

泛型方法

public class MyGenericMethod {
    public static <T> T processData(T input) {
        // 处理逻辑
        return input;
    }
}

上面的代码中,MyGenericMethod 是一个包含泛型方法的类,其中使用 T 来表示类型参数。调用该方法时,可以指定具体类型,例如:

String result = MyGenericMethod.<String>processData("hello world"); // 返回值为"hello world"

不指定具体类型时,编译器会自动根据传入的参数类型推断出类型参数。

泛型边界

public class MyGenericBound<T extends Number> {
    private T data;

    public MyGenericBound(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void plusData(T input) {
        data = (T) new Double(data.doubleValue() + input.doubleValue()); // 这里的强制类型转换有点奇怪,仅为了示例
    }
}

上面的代码中,MyGenericBound 是一个泛型类,使用 T extends Number 来表示类型参数必须是 Number 的子类型。在类的实例化时,只能指定 Number 的子类类型,例如:

MyGenericBound<Integer> integerGeneric = new MyGenericBound<>(10);
integerGeneric.plusData(5); // 实际上执行的是10 + 5
Integer data = integerGeneric.getData(); // 返回值为15

如何避免Java泛型的坑点?

Java泛型使用时,有些坑点需要避免,例如类型擦除、泛型数组等问题。下面简单介绍一下如何避免这些问题。

类型擦除

Java泛型在编译期间会进行类型擦除,从而避免类型安全问题。但是,在某些情况下,泛型类型擦除会给代码带来一些坑。比如:

public class MyGenericClass<T> {
    private T data;

    public MyGenericClass(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

MyGenericClass<Integer> integerInstance = new MyGenericClass<>(10);

使用泛型类时,在实例化时指定了类型参数 Integer,则在编译期间,MyGenericClass 中的 T 类型会被擦除成 Object 类型。而 setData 方法中的参数类型是泛型类型 T,也会被擦除成 Object 类型。因此,使用该方法设置一个 String 类型的参数是合法的,但是在调用 getData 方法时就会抛出 ClassCastException 异常。

为了避免这个问题,可以采用以下三种方式:

  • 在方法中增加类型参数
public <U extends T> void setData(U data) {
    this.data = data;
}
  • 通过构造函数传入类型信息
public MyGenericClass(Class<T> clazz, T data) {
    this.data = clazz.cast(data);
}
  • 使用通配符
public void setData(? extends T data) {
    this.data = data;
}

上述方式中,第一种方式在方法定义时增加了类型参数,并指定类型参数必须是 T 的子类型;第二种方式通过额外传入一个 Class 类型的参数来保存类型信息;第三种方式通过通配符避免了在方法中使用泛型类型参数的问题。

泛型数组

Java中的泛型数组是被禁止的,因为泛型数组在编译期间会被擦除掉,这样就很容易导致类型安全问题。如果想要使用泛型数组,可以换用列表等容器类型来替代。例如,下面的代码就可以通过使用列表来替代数组来实现:

List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);

示例

在实际的开发中,Java泛型的使用场景是非常多的。下面给出一个示例,演示了如何使用泛型来实现一个通用的线程池。

public class MyThreadPool<T extends Runnable> {
    private int threadsNum;
    private ExecutorService executorService;

    public MyThreadPool(int threadsNum) {
        this.threadsNum = threadsNum;
        this.executorService = Executors.newFixedThreadPool(threadsNum);
    }

    public void addTask(T task) {
        executorService.submit(task);
    }

    public int getThreadsNum() {
        return threadsNum;
    }

    public void shutdown() {
        executorService.shutdown();
    }

    public static void main(String[] args) {
        MyThreadPool<Runnable> threadPool = new MyThreadPool<>(10);
        threadPool.addTask(() -> {
            System.out.println("Hello world");
        });
    }
}

上面的代码中,MyThreadPool 是一个泛型类,使用 T extends Runnable 来表示类型参数必须是 Runnable 的子类型。在 main 方法中,可以向线程池中添加任务,即将一个实现了 Runnable 接口的对象传入 addTask 方法中。

这样,就可以通过泛型来实现一个通用的线程池,可以接受任意实现了 Runnable 接口的对象。

总结

本文对Java泛型进行了详细的介绍,包括泛型类、泛型接口、泛型方法和泛型边界等方面。在避免Java泛型坑点时,应当注意类型擦除和泛型数组相关的问题。通过以上示例,我们可以看到,Java泛型的使用场景非常丰富,使用泛型可以大大提高代码的重用性和安全性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:2022最新Java泛型详解(360度无死角介绍) - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • 使用Spring AOP实现MySQL数据库读写分离案例分析(附demo)

    下面我会详细讲解“使用Spring AOP实现MySQL数据库读写分离案例分析(附demo)”的完整攻略。 简介 本文主要介绍如何利用 Spring AOP 实现 MySQL 数据库读写分离,以及涉及到的相关技术。读写分离指的是读操作和写操作分别执行在不同的 MySQL 数据库中,这样可以提高数据库的并发处理能力。 技术方案 本方案主要采用以下技术: Spr…

    Java 2023年5月20日
    00
  • Java使用synchronized实现互斥锁功能示例

    实现互斥锁是多线程编程中常见的问题,Java中提供了synchronized关键字来实现互斥锁功能。 1. synchronized基本用法 1.1 使用在方法上 在方法上使用synchronized关键字,可以实现对当前对象的方法加锁,使得同一时间只能有一个线程访问该方法。 public class SynchronizedExample { public…

    Java 2023年5月26日
    00
  • JSP技术简介

    JSP技术是运用Java语言的Web编程技术之一,以便于开发人员动态地生成HTML、XML或其他类型的Web页面。在JSP页面中,可以将静态内容、JSP标记和Java代码混合在一起来生成动态Web页面。 JSP页面结构 JSP页面以.jsp后缀作为文件后缀名。在JSP页面中,可以包含以下几种元素: 指令:指示服务器或容器如何翻译JSP页面,并且在整个页面中只…

    Java 2023年6月15日
    00
  • 利用Maven实现将代码打包成第三方公共jar包

    让我详细讲解一下利用Maven实现将代码打包成第三方公共jar包的完整攻略。 第一步:创建一个Maven项目 首先,我们需要创建一个Maven项目作为代码库。我们可以使用IDE工具,如Intellij IDEA、Eclipse等,在创建项目时选择Maven项目的模板(Maven Quickstart Archetype)。 第二步:编写代码 接下来,我们需要…

    Java 2023年5月20日
    00
  • Nginx+Tomcat实现负载均衡、动静分离的原理解析

    下面我会针对Nginx+Tomcat实现负载均衡、动静分离的原理进行一些详细的讲解,同时会提供两个实例。 负载均衡原理解析 负载均衡是一种将网络请求分配到多个服务器上,并通过算法确保均衡分配的技术。常见的负载均衡算法分为以下几种: 轮询算法:按顺序轮流分配请求给服务器,均衡地将请求分配给每个服务器。 随机算法:随机从服务器列表中选取一台服务器来处理请求。 I…

    Java 2023年5月20日
    00
  • centos下docker安装及springboot远程发布docker的方法

    安装docker的方法 安装Docker CentOS 7的默认镜像源没有包含Docker组件,因此需要手动安装。Docker仓库提供了一个安装脚本,只需输入以下命令: sudo yum install -y yum-utils device-mapper-persistent-data lvm2 \ && sudo yum-config-m…

    Java 2023年5月20日
    00
  • springSecurity之如何添加自定义过滤器

    下面是关于“如何添加自定义过滤器到springSecurity中”的完整攻略: 添加自定义过滤器 在使用springSecurity时,有时候需要添加自定义的过滤器来实现一些特定的需求。下面我们就来介绍如何添加自定义的过滤器。 定义自定义过滤器类 首先我们需要定义一个自定义过滤器类,这个过滤器类需要继承OncePerRequestFilter类,并实现doF…

    Java 2023年5月20日
    00
  • java二维数组遍历的2种代码

    下面是详细讲解“Java二维数组遍历的2种代码”的完整攻略。 什么是二维数组 二维数组是指数组中包含另一个数组序列的数组。它是一种存储表格数据的有效方式。Java 二维数组是一个矩阵式的数组,数据被组织成了行和列,因此每个元素在矩阵中都有自己的位置。 Java二维数组遍历的2种代码 1. 使用双重for循环遍历 int[][] arr = {{1,2,3},…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部