Java泛型的用法及T.class的获取过程解析

yizhihongxing

Java泛型的用法及T.class的获取过程解析

什么是泛型

泛型是Java语言中的一个重要特性,它允许我们在类或方法中预先声明使用的类型,并在实例化时指定具体的类型,从而达到代码复用的效果。

例如,在传统的Java编程中,如果要编写一个通用的Stack类,可以存储各种类型的数据,可以这样写:

public class Stack {
    private Object[] array;
    private int size;

    public Stack(int capacity) {
        this.array = new Object[capacity];
        this.size = 0;
    }

    public void push(Object item) {
        array[size++] = item;
    }

    public Object pop() {
        if (size == 0) {
            throw new RuntimeException("Stack is empty");
        }
        return array[--size];
    }
}

这个Stack类使用Object类型存储元素,但是,它有一个明显的弱点:无法在编译时检查元素类型的正确性。我们可以装入任何类型的对象,而不必遵循应有的类型约束。

使用泛型,我们可以将Stack类型参数化。例如:

public class Stack<T> {
    private T[] array;
    private int size;

    public Stack(int capacity) {
        this.array = (T[]) new Object[capacity];
        this.size = 0;
    }

    public void push(T item) {
        array[size++] = item;
    }

    public T pop() {
        if (size == 0) {
            throw new RuntimeException("Stack is empty");
        }
        return array[--size];
    }
}

这里,我们将Stack声明为一个泛型类,使用类型参数T代表类型的占位符。在实例化时,我们可以指定具体的类型,例如:

Stack<String> stackOfString = new Stack<>(10);
Stack<Integer> stackOfInteger = new Stack<>(10);

泛型类的基本用法

类型参数

泛型类的类型参数用尖括号框起来,可以在声明类时指定,如:

public class List<T> {
    // ...
}

这里的T是类型参数,可以在类中使用。泛型类有一个好处:它可以使用与类型无关的代码来定义类,并且可以在实例化时指定类型。例如:

List<Integer> list = new List<>();
...
List<String> list2 = new List<>();

方法泛型

方法泛型的声明类似于泛型类的声明,只需要在方法返回类型前加上类型参数即可:

public class Stack {
    // ...

    public <T> void push(T item) {
        // ...
    }

    public <T> T pop() {
        // ...
    }
}

这里,我们使用了类型参数T来声明方法push和pop。在调用时,可以使用具体的类型来替换T:

stack.push(100);
stack.push("Hello");

通配符类型

通配符类型是指一个泛型实参是其它泛型实参或非泛型类型的基类或接口时,使用的特殊类型。使用?表示通配符类型。例如:

public void process(List<?> list) {
    // do something
}

这里,我们使用了通配符类型?,表示list中的元素类型可以是任意类型。

获取T.class的过程

在一些泛型场景中,如果需要获取泛型参数的class对象,可以利用Java的反射机制来实现。可以通过在方法中添加一个类型参数,利用Javac的类型推断机制来获取对应的class对象。

例如,在下面的示例代码中,我们演示了如何利用T.class来创建一个泛型数组。

import java.lang.reflect.Array;

public class GenericArray<T> {
    private T[] array;

    public GenericArray(Class<T> type, int size) {
        this.array = (T[]) Array.newInstance(type, size);
    }

    public void printType() {
        System.out.println(array.getClass().getTypeName());
    }

    public static void main(String[] args) {
        GenericArray<Integer> ga = new GenericArray<>(Integer.class, 10);
        ga.printType();
    }
}

在上面的示例代码中,我们在构造器中显示地传递了类型参数Class,并利用Array.newInstance(type, size)方法创建了一个泛型数组。这里,我们可以在main方法中传递任意类型的Class对象,例如:

GenericArray<String> ga = new GenericArray<>(String.class, 10);
ga.printType();

示例1:利用泛型实现一个简单的缓存系统

下面是一个简单的缓存系统,可以缓存任意类型的对象。缓存的数据存储在一个Map中,使用泛型类型T和K代表缓存数据的类型和键类型:

import java.util.HashMap;
import java.util.Map;

public class Cache<T, K> {
    private Map<K, T> cache = new HashMap<>();

    public void put(K key, T value) {
        cache.put(key, value);
    }

    public T get(K key) {
        return cache.get(key);
    }

    public static void main(String[] args) {
        Cache<String, Integer> cache = new Cache<>();
        cache.put(1, "Hello");
        cache.put(2, "World");
        System.out.println(cache.get(1));
        System.out.println(cache.get(2));
    }
}

在上面的示例代码中,我们将泛型参数T和K用于缓存类Cache中,实现了一个简单的缓存系统。

示例2:使用泛型来实现数组转换

在下面的示例代码中,我们将一个数组中的元素转换为另一个数组中的元素,同样可以使用泛型来实现:

import java.lang.reflect.Array;

public class ArrayConverter {
    public static <T, K> K[] convert(T[] src, Class<K> type) {
        K[] dest = (K[]) Array.newInstance(type, src.length);
        for (int i = 0; i < src.length; i++) {
            dest[i] = (K) src[i];
        }
        return dest;
    }

    public static void main(String[] args) {
        Integer[] ints = {1, 2, 3};
        String[] strings = ArrayConverter.convert(ints, String.class);
        for (String s : strings) {
            System.out.println(s);
        }
    }
}

在上面的示例代码中,我们使用了方法泛型来指定方法的类型参数,并利用Java的反射机制来获取对应的class对象。在main方法中,我们使用了ArrayConverter.convert方法将数组中的元素从Integer类型转换为String类型。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java泛型的用法及T.class的获取过程解析 - Python技术站

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

相关文章

  • 手把手写Spring框架

    手把手写Spring框架攻略 如果想手写一个Spring框架,可以按照以下步骤: 1.了解Spring框架的设计原理 Spring框架的设计原理是基于反转控制(IoC)和面向切面编程(AOP)。反转控制是指通过配置文件或注解将对象的创建和依赖注入由应用程序翻转到容器来管理,而不是应用程序管理。面向切面编程则是指通过 AOP 技术,在不修改原有代码的情况下,在…

    Java 2023年5月19日
    00
  • 品味布隆过滤器的设计之美

    布隆过滤器是一个精巧而且经典的数据结构。 你可能没想到: RocketMQ、 Hbase 、Cassandra 、LevelDB 、RocksDB 这些知名项目中都有布隆过滤器的身影。 对于后端程序员来讲,学习和理解布隆过滤器有很大的必要性。来吧,我们一起品味布隆过滤器的设计之美。 1 缓存穿透 我们先来看一个商品服务查询详情的接口: public Prod…

    Java 2023年4月17日
    00
  • Java 3种方法实现进制转换

    Java 3种方法实现进制转换是一个很基础的知识点,需要掌握的细节较多。在进行进制转换时,需要将目标进制的数位按权展开,并乘以相应的权值,再将结果相加即可。Java 语言提供了多种方法来实现进制转换,下面分别进行详细讲解: 1. 常规方法 常规方法是最直接的一种进制转换方法,使用起来简单明了。Java 提供了 Integer 类中的 toBinaryStri…

    Java 2023年5月26日
    00
  • springboot启动feign项目报错:Service id not legal hostnam的解决

    下面是解决“springboot启动feign项目报错:Service id not legal hostname”的完整攻略。 问题描述 在使用Spring Boot启动Feign项目时,可能会出现以下报错信息: java.lang.IllegalArgumentException: Service id not legal hostname ([服务名]…

    Java 2023年5月20日
    00
  • SpringBoot自定义bean绑定实现

    下面我将为你介绍SpringBoot自定义bean绑定实现的完整攻略。 什么是SpringBoot自定义bean绑定 在Spring Boot中,我们可以通过简单的配置来实现自动绑定(Auto Configuration),即根据Spring Boot提供的默认约定,自动创建所需的bean。但是,有时候我们需要实现更为复杂的bean绑定,这时候就需要使用Sp…

    Java 2023年5月19日
    00
  • 解读动态数据源dynamic-datasource-spring-boot-starter使用问题

    我来为您详细讲解“解读动态数据源dynamic-datasource-spring-boot-starter使用问题”的完整攻略。 一、什么是dynamic-datasource-spring-boot-starter dynamic-datasource-spring-boot-starter是一款基于SpringBoot的动态多数据源框架,能够帮助您快速…

    Java 2023年5月19日
    00
  • IntelliJ IDEA 2020.3 EAP5:引入 ML 编码,Git Stage 支持

    下面我来为您详细讲解“IntelliJ IDEA 2020.3 EAP5:引入 ML 编码,Git Stage 支持”的完整攻略。 什么是IntelliJ IDEA 2020.3 EAP5 IntelliJ IDEA是一款由JetBrains公司开发的Java集成开发环境。2020.3是其最新版本,而EAP5是该版本的一个预览版,其中包含了一些新的特性和改进…

    Java 2023年5月20日
    00
  • java多线程编程必备volatile与synchronized深入理解

    Java多线程编程必备volatile与synchronized深入理解攻略 什么是多线程编程 在计算机科学中,多线程是指一个程序中包含了多个执行流,这些执行流可以并行执行。多线程编程可以提升程序的执行效率,提供更好的用户体验。但是,多线程编程也会带来更高的难度,因为多线程程序的行为是不确定的,可能会产生竞态条件和死锁等问题。因此,多线程编程需要程序员具备一…

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