java加强 -泛型

news2025/5/12 2:42:16

概念

定义类、接口、方法时,同时声明了一个或多个类型变量(如<E>),称为泛型类、泛型接口、泛型方法、它们统称为泛型。

语法

public class ArrayList<E>{
        
}

E可以接收不同类型的数据,可以是字符串,也可以是学生类等东西。

作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力,这样可以避免强制类型转换,及其可能出现的异常。

接下来用常见API,ArrayList集合举例

package GenericityDemo;

import java.util.ArrayList;

public class GenericDemo1 {
    public static void main(String[] args) {
//        //认识泛型
//        ArrayList list = new ArrayList();           //没有使用泛型,存储任意类型数据
//        list.add("hello");
//        list.add(100);
//        list.add(true);
//        //获取数据
//        for (int i = 0; i < list.size(); i++)
//        {
//            Object obj = list.get(i);       //必须用Object接收,因为存储的任意类型数据
//            //数据转型处理
//            String s = (String) list.get(i);//运行到整型时程序会崩,因此最好要统一数据类型
//            System.out.println(s);
//        }
        ArrayList<String> list = new ArrayList<String>();       //泛型约束,只能存储String类型数据
        list.add("hello");
        list.add("world");
        //list.add(90);     //类型不是泛型约束的类型,报错

        for (int i = 0; i < list.size(); i++)
        {
            String s = list.get(i);     //类型确定,不用转型
            System.out.println(s);      //不会出现异常
        }

    }
}

一、泛型类

泛型类(Generic Class) 是通过类型参数化定义的类,其核心作用是通过类型抽象实现代码的通用性、类型安全性和灵活性。

语法

修饰符 class 类名<类型变量,类型变量....>{

}
public class ArrayList<E>{
......
}

示例

创建一个ArrayList集合类(其实就是在自己的类里用之前的API,但接收的数据类型由我们限制)

package GenericityDemo;

import java.util.ArrayList;

public class MyArrayList <E>{
    private ArrayList list = new ArrayList();
    public boolean add(E e){
        list.add(e);
        return true;
    }
    public boolean remove(E e){
        return  list.remove(e);
    }
    @Override
    public String toString() {
        return list.toString();
    }
}
package GenericityDemo;

public class GenericDemo2 {
    public static void main(String[] args) {
        //目标:学会自定义泛型类
        //需求:模拟ArrayList集合,自定义一个集合MyArrayList
        MyArrayList<String> list = new MyArrayList<>();//jdk7支持后面不写泛型类型
        list.add("java");
        list.add("后端");
        System.out.println(list);
    }
}

类型变量建议使用大写的英文字母,常用的有:E、T、K、V等

E:常用于集合类(如 ListSet),强调泛型参数是容器内的元素。

T:当泛型类或方法不限制具体类型时,常用 T 作为默认类型占位符。

K/V:用于键值对数据结构(如 Map)中,明确区分键和值的类型。

二、泛型接口

泛型接口(Generic Interface) 是通过类型参数化定义的接口,其核心作用是通过类型抽象提高代码的复用性、类型安全性和灵活性。

修饰符 interface 接口名<类型变量,类型变量...>{
}
public interface A<E>{
...
}

示例

对学生数据/老师数据都要进行增删查改操作。

定义一个泛型接口可以接学生或老师对象进行操作,可以实现一个方法操作两个角色。

package GenericityDemo3;

public interface Data<T> {
//    void add(Student s);
//    void add(Teacher t);
    //类型约定死了,,只能存Student或Teacher
    //利用泛型接口
    void add(T t);      //此时泛型可以为Teacher也能为Student
    void delete(T t);
    void update(T t);
    T query(int id);
}

(此示例并没有真正实现增删查改操作,只为示范)

package GenericityDemo3;

public class Student {
}
package GenericityDemo3;

public class Teacher {
}

创造两个类用于实现Data,一个实现老师操作,一个实现学生操作

package GenericityDemo3;

public class TeacherData implements Data<Teacher>{
    //操作老师数据
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public void delete(Teacher teacher) {

    }

    @Override
    public void update(Teacher teacher) {

    }

    @Override
    public Teacher query(int id) {
        return null;
    }
}
package GenericityDemo3;

public class StudentData implements Data<Student>{
    //专门操作学生对象

    @Override
    public void add(Student student) {

    }

    @Override
    public void delete(Student student) {

    }

    @Override
    public void update(Student student) {

    }

    @Override
    public Student query(int id) {
        return null;
    }
}
package GenericityDemo3;

public class GenericDemo3 {
    public static void main(String[] args) {
        //目标:搞清楚泛型接口的基本应用
        //需求:项目需要对学生数据/老师数据都要进行增删查改操作
        StudentData studentData = new StudentData();
        studentData.add(new Student());      //添加学生数据.对学生操作
        Student s = studentData.query(1001);
    }
}

通过泛型接口,可以为不同类型的数据定义统一的处理逻辑,同时避免强制类型转换和运行时类型错误。

三、泛型方法

泛型方法(Generic Method) 是通过在方法签名中声明类型参数来实现的方法级别泛型化。它与泛型类的主要区别在于作用范围:泛型方法的类型参数仅作用于该方法内部,而非整个类。

语法

修饰符<类型变量,类型变量,...>返回值类型 方法名(形参列表){


}

示例

现在我需要一个方法将数组的内容打印出来

package GenericDemo4;


public class GenericDemo4 {
    //目标:理解泛型方法
    public static void main(String[] args) {
        //需求:打印任意数组的内容

        String[] arr1 = {"hello","world","java"};
        printArray(arr1);
       
        Student[] arr2 = new Student[3];
        //printArray(arr2);//只能接收String类型数组
        Student s1 = getMax(arr2); 
        printArray2(arr1);
        getMax(arr2);       //泛型方法,可以接收任意类型的数组,避免强转
    }
    public static  void printArray(String[] arr)
    {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i] + " ");
        }
    }
    public static <T> void printArray2(T[] arr)
    {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i] + " ");
        }
    }
    public static <T> T getMax(T[] name)
    {
        return null;
    }
}

上述代码有两个方法,一个是printArray一个是printArray2,但printArray有一个缺点就是只能打印字符串数组的内容,若是其他数组则无法接收。因此,我们可以做一个泛型方法即printArray2,它可以接收String数组也可以接收Student数组,实现了一个方法解决多个问题。

四、通配符与上下限

当我们要传的参数为多个集合,每个集合都是继承于某个父类的子类的集合时,我们就可以通过使用通配符来接收不同的子类集合。(注:例如两个集合为ArrayList<Cat>和ArrayList<Dog>,不能用ArrayList<Animal>接收,因为他们本质上是不同的集合,虽然他们的子类继承了同一个父类)

示例

package GenericDemo4;

public class Car {
}
package GenericDemo4;

public class BYD extends Car{

}
package GenericDemo4;

public class BMW extends Car{
}
package GenericDemo4;

import java.util.ArrayList;

public class GenericDemo5 {
    public static void main(String[] args) {
        //目标:理解通配符和上下限
        ArrayList<BYD> byds = new ArrayList<>();
        byds.add(new BYD());
        byds.add(new BYD());
        byds.add(new BYD());
        //go(byds);           //报错不具备通用性
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

    }
    //模拟极品飞车游戏
    //虽然比亚迪和宝马是Car的子类,但ArrayList<BYD>和ArrayList<BMW>和ArrayList<Car>是不同的,因此不能用多态
//    public static void go(ArrayList<BMW> cars)
//    {
//
//    }
    //通配符,在使用泛型时代表一切类型
   
    public static void go(ArrayList<?> cars)
    {
    }
}

然而,若是这么写这个方法能接收的集合范围又太大了,连猫和狗都可以进这个开汽车的方法,因此需要使用上下限来加以限制。

? extends Car ?能接收Car或者Car的子类(泛型上限)
? super Car ?能接收Car或者Car的父类(泛型下限)

package GenericDemo4;

import java.util.ArrayList;

public class GenericDemo5 {
    public static void main(String[] args) {
        //目标:理解通配符和上下限
        ArrayList<BYD> byds = new ArrayList<>();
        byds.add(new BYD());
        byds.add(new BYD());
        byds.add(new BYD());
        //go(byds);           //报错不具备通用性
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

    }
    //模拟极品飞车游戏
    //虽然比亚迪和宝马是Car的子类,但ArrayList<BYD>和ArrayList<BMW>和ArrayList<Car>是不同的,因此不能用多态
//    public static void go(ArrayList<BMW> cars)
//    {
//
//    }
    //通配符,在使用泛型时代表一切类型
    //为了防止将狗,猫等不属于车的类型传入方法,使用泛型的上下限限制
    //? extends Car ?能接收Car或者Car的子类(泛型上限)
    //? super Car ?能接收Car或者Car的父类(泛型下限)
    public static void go(ArrayList<? extends Car> cars)
    {
    }
}

这样,就能将这个方法限制在接收汽车类的子类了。

五、泛型支持的数据类型

泛型不支持基本的数据类型,即int,double等数据类型,原因是泛型工作在编译阶段,编译结束后系统会进行泛型擦除,所有类型都会转变为Object类型。而Object是对象类型,接收的是对象,数字等类型不是对象,因此不接收基本的数据类型。为了能够兼容基本的数据类型,java的库里添加了包装类,用于将基本数据类型变为对象。

包装类有8种。

int -> Integer char -> Character ,其它的都是首字母大小写。

package GenericDemo5;

import java.util.ArrayList;
import java.util.Objects;

public class GenericDemo5 {
    public static void main(String[] args) {
        //目标:搞清楚泛型和集合不支持基本数据类型,只能支持对象类型(引用类型)

        //ArrayList<double> list = new ArrayList<>();   //报错,不支持
        //泛型擦除:泛型工作在编译阶段,等编译后泛型就没用了,所以泛型在编译后都会被擦除。所有类型会恢复为Object类型。
        //Object是对象类型,不能直接指向某个数,只能指向某个对象。
        //因此要使用包装类,比如Integer、Double、Character、Boolean等。
        //包装类的作用:把基本数据类型包装成对象类型。
        //ArrayList<int> list = new ArrayList<>();
        //list.add(12);     //12不是对象,报错
        ArrayList<Integer> list = new ArrayList<>();
        list.add(12);           //自动装箱,把基本数据类型12包装成Integer对象。
        int rs= list.get(0);        //自动拆箱,把Integer对象12拆箱成基本数据类型。

        //把基本数据类型变成包装类对象
        //手工包装
        //Integer i = new Integer(12);//从jdk9开始,这个方法被淘汰了(过时)
        //推荐用valueOf的原因:valueOf方法中缓存了-128~127的数值,重复创建这个范围内的数字时不会创建新对象,而是直接返回缓存中的对象。
        //缓存对象范围是-128~127,如果超过这个范围,就会创建新的对象。
        //更优雅,节约内存。
        Integer i = Integer.valueOf(12);    //此时i为对象,里面存储的是12
        Integer i2 = Integer.valueOf(12);
        System.out.println(i == i2);        //ture, 因为i和i2是同一个对象
        //自动装箱
        Integer i3 = 12;        //与Integer i = Integer.valueOf(12)一个意思
        Integer i4 = 12;
        System.out.println(i3 == i4);
        //自动拆箱:把包装类型的对象直接给基本类型的数据
        int i5 = i3;
        System.out.println(i5);
        System.out.println("========================================================");
        //包装类新增的功能
        //1、把基本类型的数据变成字符串
        int j=23;
        String rs1 = Integer.toString(j);
        System.out.println(rs1+1);      //不是24,说明已经是字符串
        Integer i6=j;
        String rs2 = i6.toString();
        System.out.println(rs2+1);
        String  rs3 = i6+"";        //直接加""转换为字符串
        System.out.println(rs3+1);
        System.out.println("========================================================");
        //把字符串数值转换成对应的基本数据类型
        String str = "123";
        int i1 = Integer.parseInt(str);
        int i9 = Integer.valueOf(str);
        System.out.println(i1+1);
        System.out.println(i9+1);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SEMI E40-0200 STANDARD FOR PROCESSING MANAGEMENT(加工管理标准)-(二)

8 行为规范 8.1 本章定义监督实体&#xff08;Supervisor&#xff09;与加工资源&#xff08;Processing Resource&#xff09;为实现物料加工所需的高层级通信逻辑&#xff0c;不涉及具体消息细节&#xff08;详见第10章消息服务&#xff09;。 8.2 加工任务通信 8.2.1 加工…

根据窗口大小自动调整页面缩放比例,并保持居中显示

vue 项目 直接上代码 图片u1.png 是个背景图片 图片u2.png 是个遮罩 <template><div id"app"><div class"viewBox"><divclass"screen":style"{ transform: translate(-50%,-50%…

Android SDK 国内镜像及配置方法(2025最新,包好使!)

2025最新android sdk下载配置 1、首先你需要有android sdk manager2、 直接上教程修改hosts文件配置域名映射即可(不用FQ)2.1 获取ping dl.google.com域名ip地址2.2 配置hosts文件域名映射2.3 可以随意下载你需要的sdk3、 总结:走过弯路,踩过坑!!!大家就不要踩了!避坑1…

【Python开源】深度解析:一款高效音频封面批量删除工具的设计与实现

&#x1f3b5; 【Python开源】深度解析&#xff1a;一款高效音频封面批量删除工具的设计与实现 &#x1f308; 个人主页&#xff1a;创客白泽 - CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f40d;《Python开源项目实战》 &#x1f4a1; 热爱不止于代码&#xff0c;热情…

OpenStack Yoga版安装笔记(26)实例元数据笔记

一、实例元数据概述 1.1 元数据 &#xff08;官方文档&#xff1a;Metadata — nova 25.2.2.dev5 documentation&#xff09; Nova 通过一种叫做元数据&#xff08;metadata&#xff09;的机制向其启动的实例提供配置信息。这些机制通常通过诸如 cloud-init 这样的初始化软件…

【Linux】swap交换分区管理

目录 一、Swap 交换分区的功能 二、swap 交换分区的典型大小的设置 2.1 查看交换分区的大小 2.1.1 free 2.1.2 cat /proc/swaps 或 swapon -s 2.1.3 top 三、使用交换分区的整体流程 3.1 案例一 3.2 案例二 一、Swap 交换分区的功能 计算机运行一个程序首先会将外存&am…

VirtualBox 创建虚拟机并安装 Ubuntu 系统详细指南

VirtualBox 创建虚拟机并安装 Ubuntu 系统详细指南 一、准备工作1. 下载 Ubuntu 镜像2. 安装 VirtualBox二、创建虚拟机1. 新建虚拟机2. 分配内存3. 创建虚拟硬盘三、配置虚拟机1. 加载 Ubuntu 镜像2. 调整处理器核心数(可选)3. 启用 3D 加速(图形优化)四、安装 Ubuntu 系统…

触想CX-3588工控主板应用于移动AI数字人,赋能新型智能交互

一、行业发展背景 随着AI智能、自主导航和透明屏显示等技术的不断进步&#xff0c;以及用户对“拟人化”、“沉浸式”交互体验的期待&#xff0c;一种新型交互终端——“移动AI数字人”正在加速实现规模化商用。 各大展厅展馆、零售导购、教学政务甚至家庭场景中&#xff0c;移…

【深入浅出MySQL】之数据类型介绍

【深入浅出MySQL】之数据类型介绍 MySQL中常见的数据类型一览为什么需要如此多的数据类型数值类型BIT&#xff08;M&#xff09;类型INT类型TINYINT类型BIGINT类型浮点数类型float类型DECIMAL(M,D)类型区别总结 字符串类型CHAR类型VARCHAR(M)类型 日期和时间类型enum和set类型 …

Vue3响应式:effect作用域

# Vue3响应式: effect作用域 什么是Vue3响应式&#xff1f; 是一款流行的JavaScript框架&#xff0c;它提供了响应式和组件化的视图组织方式。在Vue3中&#xff0c;响应式是一种让数据变化自动反映在视图上的机制。当数据发生变化时&#xff0c;与之相关的视图会自动更新。 作用…

25.5.4数据结构|哈夫曼树 学习笔记

知识点前言 一、搞清楚概念 ●权&#xff1a;___________ ●带权路径长度&#xff1a;__________ WPL所有的叶子结点的权值*路径长度之和 ●前缀编码&#xff1a;____________ 二、构造哈夫曼树 n个带权值的结点&#xff0c;构造哈夫曼树算法&#xff1a; 1、转化成n棵树组成的…

RabbitMQ 深度解析:从核心组件到复杂应用场景

一.RabbitMQ简单介绍 消息队列作为分布式系统中不可或缺的组件&#xff0c;承担着解耦系统组件、保障数据可靠传输、提高系统吞吐量等重要职责。在众多消息队列产品中&#xff0c;RabbitMQ 凭借其可靠性和丰富的特性&#xff0c;在企业级应用中获得了广泛应用。 二.RabbitMQ …

【Linux笔记】系统的延迟任务、定时任务极其相关命令(at、crontab极其黑白名单等)

一、延时任务 1、概念 延时任务&#xff08;Delayed Jobs&#xff09;通常指在指定时间或特定条件满足后执行的任务。常见的实现方式包括 at 和 batch 命令&#xff0c;以及结合 cron 的调度功能。 2、命令 延时任务的命令最常用的是at命令&#xff0c;第二大节会详细介绍。…

使用阿里AI的API接口实现图片内容提取功能

参考链接地址&#xff1a;如何使用Qwen-VL模型_大模型服务平台百炼(Model Studio)-阿里云帮助中心 在windows下&#xff0c;使用python语言测试&#xff0c;版本&#xff1a;Python 3.8.9 一. 使用QVQ模型解决图片数学难题 import os import base64 import requests# base 64 …

从零开始搭建你的个人博客:使用 GitHub Pages 免费部署静态网站

&#x1f310; 从零开始搭建你的个人博客&#xff1a;使用 GitHub Pages 免费部署静态网站 在互联网时代&#xff0c;拥有一个属于自己的网站不仅是一种展示方式&#xff0c;更是一种技术能力的体现。今天我们将一步步学习如何通过 GitHub Pages 搭建一个免费的个人博客或简历…

C#串口通信

在C#中使用串口通信比较方便&#xff0c;.Net 提供了现成的类&#xff0c; SerialPort类。 本文不对原理啥的进行介绍&#xff0c;只介绍SerialPort类的使用。 SerialProt类内部是调用了CreateFile&#xff0c;WriteFile等WinAPI函数来实现串口通信。 在后期的Windows编程系…

服务器配置llama-factory问题解决

在配置运行llama-factory&#xff0c;环境问题后显示环境问题。这边给大家附上连接&#xff0c;我们的是liunx环境但是还是一样的。大家也记得先配置虚拟环境。 LLaMA-Factory部署以及微调大模型_llamafactory微调大模型-CSDN博客 之后大家看看遇到的问题是不是我这样。 AI搜索…

Spring Boot + Vue 实现在线视频教育平台

一、项目技术选型 前端技术&#xff1a; HTML CSS JavaScript Vue.js 前端框架 后端技术&#xff1a; Spring Boot 轻量级后端框架 MyBatis 持久层框架 数据库&#xff1a; MySQL 5.x / 8.0 开发环境&#xff1a; IDE&#xff1a;Eclipse / IntelliJ IDEA JDK&…

使用Jmeter进行核心API压力测试

最近公司有发布会&#xff0c;需要对全链路比较核心的API的进行压测&#xff0c;今天正好分享下压测软件Jmeter的使用。 一、什么是Jmeter? JMeter 是 Apache 旗下的基于 Java 的开源性能测试工具。最初被设计用于 Web 应用测试&#xff0c;现已扩展到可测试多种不同的应用程…

JavaScript中数组和对象不同遍历方法的顺序规则

在JavaScript中&#xff0c;不同遍历方法的顺序规则和适用场景存在显著差异。以下是主要方法的遍历顺序总结&#xff1a; 一、数组遍历方法 for循环 • 严格按数组索引顺序遍历&#xff08;0 → length-1&#xff09; • 支持break和continue中断循环 • 性能最优&#xff0c;…