java加强 -泛型

概念

定义类、接口、方法时,同时声明了一个或多个类型变量(如<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);}@Overridepublic String toString() {return list.toString();}
}
package GenericityDemo;public class GenericDemo2 {public static void main(String[] args) {//目标:学会自定义泛型类//需求:模拟ArrayList集合,自定义一个集合MyArrayListMyArrayList<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也能为Studentvoid 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>{//操作老师数据@Overridepublic void add(Teacher teacher) {}@Overridepublic void delete(Teacher teacher) {}@Overridepublic void update(Teacher teacher) {}@Overridepublic Teacher query(int id) {return null;}
}
package GenericityDemo3;public class StudentData implements Data<Student>{//专门操作学生对象@Overridepublic void add(Student student) {}@Overridepublic void delete(Student student) {}@Overridepublic void update(Student student) {}@Overridepublic 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为对象,里面存储的是12Integer 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.mzph.cn/bicheng/80187.shtml

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

相关文章

C++ 项目 -- 高并发内存池

目录 项目介绍 内存池概念 池化技术 内存池 内存池主要解决的问题 malloc 定长内存池 申请内存 释放内存 整体框架设计 thread cache 申请内存 释放内存 central cache 申请内存 释放内存 page cache 申请内存 释放内存 大块内存申请实现 定长内存…

高效C/C++之九:Coverity修复问题:关于数组操作 和 内存操作

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 高效C/C之九&#xff1a;Coverity修复问题&#xff1a;关于数组操作 和 内存操作 目录 【关注我&#xff0c;后…

vfrom表单设计器使用事件机制控制字段显示隐藏

1. 使用表单设计器进行debug调试 依据 vform3.0开发者文档 https://www.ganweicloud.com/docs/6.1.0/pages/d3e6d9/ 对switch组件设置事件逻辑 调试中

iPhone 和 Android 在日期格式方面的区别

整篇文章由iPhone 和 Android 在日期格式方面有所不同引起,大致介绍了,两种时间标准,以及在 JavaScript 下的格式转换方法。 Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 iPhone 和 Android 在日期格式方面有所不同。其中,iPhone(iOS)使…

985高校查重率“隐性阈值”:低于5%可能被重点审查!

你是不是也以为&#xff1a; “查重率越低越好&#xff0c;最好压到1%、0%&#xff0c;导师看了都感动哭&#x1f979;” 但是你不知道的是——在985/211等重点高校&#xff0c;查重率太低反而可能引起导师和学术办公室的“特别关注”&#xff01; 今天就来扒一扒这个查重圈“…

【NLP】33. Pinecone + OpenAI :构建自定义语义搜索系统

Pinecone OpenAI 中文教学教程&#xff1a;构建自定义语义搜索系统 一、背景介绍 当下 AI 问答系统、矩阵检索、短文本分类等场景中&#xff0c;都需要很好地实现 “根据输入进行相似给点搜索”。这种算法基础称为 “向量搜索”&#xff0c;它的核心是将文本转换为向量后&am…

【Mybatis-plus常用语法】

MyBatis-Plus 是 MyBatis 的增强工具&#xff0c;提供了很多便捷的功能来简化开发。以下是一些 MyBatis-Plus 的常见语法&#xff1a; 实体类注解&#xff1a;使用 TableName 注解来指定实体类和数据库表的映射关系。 TableName("user") public class User {privat…

Logback官方文档翻译章节目录

Logback官方文档翻译章节目录 第一章 Logback简介 第二章 Logback的架构&#xff08;一&#xff09; Logback的架构&#xff08;二&#xff09; Logback的架构&#xff08;三&#xff09; 持续更新中…

Python变量作用域

变量作用域是Python编程中非常重要的基础概念&#xff0c;理解它可以帮助你避免很多常见的错误。本文将用简单易懂的方式&#xff0c;带你全面掌握Python变量作用域的所有细节。 一、什么是变量作用域&#xff1f; 变量作用域&#xff08;Scope&#xff09;指的是变量在程序中…

初学者的AI智能体课程:构建AI智能体的十堂课

初学者的AI智能体课程:构建AI智能体的十堂课 在人工智能(AI)领域,AI智能体正在逐渐发挥其不容忽视的作用。自动化的智能体不仅仅在理论上广泛讨论,更加在实际应用中开辟了一片新的天地。那么如何动手开发属于自己的AI智能体呢?Microsoft提供的AI智能体入门课正是为此而设…

【并发编程】MySQL锁及单机锁实现

目录 一、MySQL锁机制 1.1 按锁粒度划分 1.2 按锁功能划分 1.3 InnoDB锁实现机制 (1)记录锁(Record Lock) (2) 间隙锁(Gap Lock) (3) 临键锁(Next-Key Lock) (4) 插入意向锁(Insert Intention Lock) 二、基于 JVM 本地锁实现,保证线程安全 2.1 线程不安全的分析 2.1…

能耗优化新引擎:EIOT平台助力企业降本增效

安科瑞顾强 数字化转型的背景下&#xff0c;能源管理正加速向智能化、远程化方向演进。安科瑞电气推出的EIOT托管平台及ADW300系列4G无线计量仪表&#xff0c;通过云端技术与无线通信的深度融合&#xff0c;为用户打造了高效、便捷的远程能源监测与管理体系&#xff0c;助力企…

(14)Element Plus项目综合案例

本系列教程目录&#xff1a;Vue3Element Plus全套学习笔记-目录大纲 文章目录 第3章 综合案例3.1 搭建项目3.1.1 创建Vite工程3.1.2 配置路由 3.2 登录模块页面3.2.1 注册页面3.2.2 登录页面3.2.3 忘记密码页面 3.3 导航设置3.3.1 头部3.3.2 侧边栏与底部1&#xff09;头像部分…

Webug4.0靶场通关笔记22- 第27关文件包含

目录 一、文件包含 1、原理分析 2、文件包含函数 &#xff08;1&#xff09;include( ) &#xff08;2&#xff09;include_once( ) &#xff08;3&#xff09;require( ) &#xff08;4&#xff09;require_once( ) 二、第27关渗透实战 1、打开靶场 2、源码分析 3、…

〖 Linux 〗解决 VS Code 远程连接服务器的常见问题

文章目录 解决 VS Code 远程连接服务器的断开问题VS Code Remote-SSH一直弹出输入密码的问题VsCode C 语法检测失效不标红色波浪线 解决办法卸载扩展方式&#xff1a; 解决vscode C智能提示缓慢 解决 VS Code 远程连接服务器的断开问题 解决 vscode 卡顿&#xff0c;卡死&…

ERC-20与ERC-721:区块链代币标准的双星解析

一、代币标准的诞生背景 在以太坊生态中&#xff0c;代币标准是构建去中心化应用&#xff08;DApps&#xff09;的基石。ERC-20与ERC-721分别代表同质化与非同质化代币的两大核心标准&#xff0c;前者支撑着90%以上的加密资产流通&#xff0c;后者则开启了数字资产唯一性的新时…

C++入门小馆 :多态

嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的pa…

【NextPilot日志移植】整体功能概要

整体日志系统的实现功能 该日志系统主要实现了飞行日志的记录功能&#xff0c;支持多种日志记录模式&#xff0c;可将日志存储到文件或通过 MAVLink 协议传输&#xff0c;同时具备日志加密、空间管理、事件记录等功能。具体如下&#xff1a; 日志记录模式&#xff1a;支持按武…

数字化转型:概念性名词浅谈(第二十五讲)

大家好&#xff0c;今天接着介绍数字化转型的概念性名词系列。 &#xff08;1&#xff09;SOP(标准作业程序) 标准作业程序&#xff08;Standard Operating Procedure, SOPs&#xff09;是在有限时间与资源内&#xff0c;为了执行复杂的日常事务所设计的内部程序。从管理学的…

交叉编译 opencv-4.10

编译说明 opencv 下包含很多模块&#xff0c;各个模块的作用可以参考Opencv—模块概览. 嵌入式考虑有限存储等因素会对模块进行裁剪&#xff0c;我这里主要保留图像拼接&#xff08;stitching&#xff09;图片编解码&#xff08;imgcodecs&#xff09;与特征点匹配&#xff08…