Java泛型:灵活多变的类型参数化工具

  • 👑专栏内容:Java
  • ⛪个人主页:子夜的星的主页
  • 💕座右铭:前路未远,步履不停

目录


一、泛型

1、什么是泛型

在传统的编程方法中,类和方法通常被限定为使用特定的类型。这些类型可能是基础的数据类型(如整数、字符等),或者是由程序员自己定义的复杂类型。这种方式在处理单一类型数据时很有效,但当我们需要编写更加灵活、能够适用于多种数据类型的代码时,这种严格的类型限制就变成了一个约束。

泛型,就是为了解决这种限制而生的。简单来说,泛型可以理解为一种"类型模板",它允许程序员编写的代码能够适应不同的数据类型,而不必为每种可能的数据类型都编写一个新版本。

泛型的厉害之处,就在于它的灵活性和重用性。你可以写一个泛型方法或类,然后在需要的时候用具体的类型去实例化它,比如整数、字符串或者是你自定义的任何类型。这样,你就可以用同一套代码处理不同类型的数据,极大地提高了代码的通用性和可维护性。

2、泛型的语法

泛型的基本语法主要包括以下几个方面:

  1. 泛型类和接口:

    • 在类或接口后面加上<T>来声明一个泛型类或接口。

    • T是类型参数,代表一种未指定的类型。在实例化类或接口时,你可以用具体的类型替换它。

    • 示例:

      java 复制代码
      public class Box<T> {
          private T t;
      
          public void set(T t) {
              this.t = t;
          }
      
          public T get() {
              return t;
          }
      }

    这个例子中,Box类可以用任何类型的对象来实例化,例如Box<Integer>或Box<String>。

  2. 泛型方法:

    • 泛型方法可以定义在普通类中,也可以定义在泛型类中。

    • 在方法返回类型之前使用<T>来声明一个泛型方法。

    • 示例:

      java 复制代码
      public <T> T genericMethod(T t) {
          return t;
      }

    这个方法可以接受任何类型的参数,并返回相同类型的对象。

  3. 类型通配符:

    • 使用?表示未知类型,通常用在参数、字段、局部变量上,以及泛型方法的返回类型上。

    • 示例:

      java 复制代码
      public void processElements(List<?> elements) {
          for (Object e : elements) {
              // 处理e
          }
      }

    List<?>可以接受任何类型的List。

  4. 限定的类型参数:

    • 你可以限制类型参数可以接受的类型范围。

    • 使用extends关键字来限定类型参数的上界(即它必须是特定类或接口的子类型)。

    • 示例:

      java 复制代码
      public <T extends Number> double sum(List<T> numbers) {
          double sum = 0.0;
          for (Number n : numbers) {
              sum += n.doubleValue();
          }
          return sum;
      }

这个方法只接受Number类型或其子类的List。

泛型存在的意义:

  • 在编译的时候,帮我们进行类型的检查。
  • 在编译的时候,帮我们进行类型的转换。

二、泛型类的使用

1、泛型类的语法

java 复制代码
泛型类<类型实参> 变量名; // 定义一个泛型类引用

new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象
java 复制代码
MyArray<Integer> list = new MyArray<Integer>();

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

2、泛型如何编译的

2.1、擦除机制

在编译时,Java编译器将所有的泛型类型参数替换掉,这个过程就是类型擦除。

  • 泛型类型参数被替换为它们的边界或者Object。
  • 如果类型参数是有界的(<T extends Number>),编译器将类型参数替换为它的第一个边界。
  • 如果类型参数是无界的(<T>),编译器将类型参数替换为Object。

Java的泛型机制是在编译级别实现的,编译器生成的字节码在运行期间并不包含泛型的类型信息。

2.2、为什么不能实例化泛型类型数组

java 复制代码
class MyArray<T> {
    public T[] array = (T[])new Object[10];
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public T[] getArray() {
        return array;
    }
}

public class demo1 {
    public static void main(String[] args) {
        MyArray<Integer> myArray1 = new MyArray<>();
        Integer[] strings = myArray1.getArray();
    }
}

由于类型擦除的原因,不能直接创建一个泛型数组。类型擦除会将泛型类型参数T替换为Object,这导致了类型不匹配,从而在运行时抛出ClassCastException。

3、泛型方法

语法:方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

例子:写一个泛型方法,用于交换数组中两个元素的位置:

java 复制代码
public class GenericMethodTest {
    // 泛型方法 printArray
    public static < E > void printArray( E[] inputArray ) {
        for(E element : inputArray) {
            System.out.printf("%s ", element);
        }
        System.out.println();
    }

    public static void main(String args[]) {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

        System.out.println("整型数组元素为:");
        printArray(intArray);   // 传递一个整型数组

        System.out.println("\n双精度型数组元素为:");
        printArray(doubleArray);   // 传递一个双精度型数组

        System.out.println("\n字符型数组元素为:");
        printArray(charArray);   // 传递一个字符型数组
    }
}
  • 泛型方法可以声明在普通类或泛型类中。
  • 泛型方法的声明包括一个类型参数部分,跟在方法的修饰符和返回类型之前。
  • 类型参数部分是一个尖括号括起来的类型参数列表,如<T>。
相关推荐
木井巳5 小时前
【动态规划】三步问题
java·算法·leetcode·动态规划·推荐算法
小张成长计划..5 小时前
【Linux】25:线程概念和控制
java·linux·jvm
蛋蛋的就会顺顺的14 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
需要82615 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡15 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
伯恩bourne17 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
silvamux_17 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
省钱兄--zs18 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构
顽疲18 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog18 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友