泛型的初步认识(1)

前言~🥳🎉🎉🎉   

hellohello~,大家好💕💕,这里是E绵绵呀✋✋ ,如果觉得这篇文章还不错的话还请点赞❤️❤️收藏💞 💞 关注💥💥,如果发现这篇文章有问题的话,欢迎各位评论留言指正,大家一起加油!一起chin up!👍👍 

💥个人主页:E绵绵的博客
💥所属专栏:JAVA知识点专栏   JAVA题目练习  c语言知识点专栏   c语言题目练习

❤️❤️这篇文章我们将初步介绍下泛型,其知识点可能有点复杂,还请各位认真看完整篇文章。那么我们开始出发吧 !

参考文章:Java 中的泛型(两万字超全详解)_java 泛型-CSDN博客

 什么是泛型

泛型的标志通常使用尖括号 “<>” 来表示,尖括号中可以包含一个或多个  类型参数或类型形参。 

泛型类型形参一般使用一个大写字母表示,常用的名称有:T E K V .

泛型类型参数只能是引用类型,不能是基本类型如果需要使用基本类型,可以使用对应的包装类如Integer,Double。通俗讲就是<>内部只能时引用类型。

通过泛型指定的类型参数来控制泛型形参的具体类型,一旦传入了具体的类型参数后,泛型形参的类型将被限制为这个具体的类型参数,而之后如果出现将不匹配的数据类型配给限制后的类型参数,编译器就会直接报错。这个被称之为类型检查:泛型提供了编译时类型检查,可以在编译时捕获类型错误,避免在运行时出现类型不匹配的错误。

泛型可以应用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法,之后将一一介绍。

我们使用泛型的好处在于可以提高代码的重用性和安全性,避免了类型转换的错误和运行时异常。泛型可以让代码更加简洁、清晰,同时也可以提高代码的可读性和可维护性。

 泛型类 

泛型类的定义 

❤️❤️ <>用于类的定义中,则该类被称为泛型类.

class 类名<类型参数1, 类型参数2, ...> {// 类的成员和方法
}

在类的成员和方法中,可以使用这些类型参数来定义变量、方法参数、返回值等。

泛型类的使用

public class Main<T> { private T key;public Generic(T key) { this.key = key;}public T getKey(){ return key;}
}

假设有个泛型类如上,在使用该泛型类时,我们通过实例化该泛型类对象去指定具体的类型来替换泛型参数。

例如,Main<Integer> myObj = new Main<Integer>();表示创建了一个Main泛型类的对象myObj,并指定该对象的泛型参数为Integer。当指定该对象为 Integer 类型时,原泛型类可以想象它会自动扩展,用它创建出的对象的类型参数会被替换为Integer。

  🎯🎯扩展: 

1.  我们还可以用以下方式创建泛型类对象:MyArray<Integer> list = new MyArray<>(); 此时编译器可以根据上下文推导出类型实参,所以可以省略类型实参的填写 ,在这例子中可以推导出实例化需要的类型实参为 Integer。

Java的类型推导是指在编程过程中,编译器能够根据上下文自动推断出变量的类型,而无需显式地指定类型。类型推导的优点是可以减少冗余的代码,提高代码的可读性。但也需要注意不要滥用类型推导,应该在保证代码可读性的前提下使用。

 2.在泛型类的创建中我们还可以在<>中什么都不传入,此时则默认是 < Object >如 MyArray list = new MyArray()相当于MyArray<Object> list = new MyArray<Object>()。

泛型类的注意事项 

🎯🎯泛型类中的静态方法和静态变量不可以使用泛型类所声明的类型参数,否则会报错。

这是因为泛型类中的类型参数的确定是在创建泛型类对象的时候,而静态变量和静态方法在类加载时已经初始化,直接使用类名调用;在泛型类的类型参数未确定时,静态成员有可能被调用,因此泛型类的类型参数是不能在静态成员中使用的。

 泛型接口

泛型接口的定义 

  泛型接口和泛型类的定义差不多,基本语法如下:

public interface 接口名<类型参数> {...
}

   举例如下:

public interface Inter<T> {public abstract void show(T t) ;
}

泛型接口的注意事项 

  🎯🎯在泛型接口中,静态成员也不能使用泛型接口定义的类型参数。

  接口的成员变量默认都是static类型,所以不能使用类型参数,而在接口的三大方法中,        default方法和抽象方法都能使用类型参数,静态方法自然不能使用类型参数。

interface IUsb<U, R> {int n = 10;U name;// 报错! 接口中的属性默认是静态的,因此不能使用类型参数声明R get(U u);// 抽象方法中,可以使用类型参数R static put(U u){; 
}//报错!不能在静态方法中使用类型参数// 在jdk8 中,可以在接口中使用默认方法, 默认方法可以使用泛型接口的类型参数default R method(U u) {return null;}
}

泛型接口的使用 

❤️❤️因为接口不能被实例化,所以该泛型接口中的类型参数,是在在该接口被继承或者被实现时确定。使用如下:

 ❤️❤️ 我们先定义一个泛型接口

interface IUsb<U, R> {R get(U u);void hi(R r);default R method(U u) {return null;}
}

1.我们能定义一个接口 IA 继承了 泛型接口 IUsb,在 接口 IA 定义时必须确定泛型接口 IUsb 中的类型参数。 

// 在继承泛型接口时,必须确定泛型接口的类型参数
interface IA extends IUsb<String, Double> {...
}// 当去实现 IA 接口时,因为 IA 在继承 IUsu 接口时,指定了类型参数 U 为 String,R 为 Double
// 所以在实现 IUsb 接口的方法时,使用 String 替换 U,用 Double 替换 R
class AA implements IA {@Overridepublic Double get(String s) {return null;}@Overridepublic void hi(Double d) {...}
}

2.定义一个类 BB 实现了 泛型接口 IUsb,在 类 BB 定义时需要确定泛型接口 IUsb 中的类型参数。

// 实现接口时,需要指定泛型接口的类型参数
// 给 U 指定 Integer, 给 R 指定了 Float
// 所以,当我们实现 IUsb 方法时,会使用 Integer 替换 U, 使用 Float 替换 R
class BB implements IUsb<Integer, Float> {@Overridepublic Float get(Integer integer) {return null;}@Overridepublic void hi(Float afloat) {...}
}

 3.定义一个类 CC 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,则默认为 Object。

// 实现泛型接口时没有确定类型参数,则默认为 Object
// 建议直接写成 IUsb<Object, Object>
class CC implements IUsb {//等价 class CC implements IUsb<Object, Object> @Overridepublic Object get(Object o) {return null;}@Overridepublic void hi(Object o) {...}
}

 4.如果定义一个类 DD 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,也可以将 DD 类也定义为泛型类,泛型类声明的类型参数必须有接口 IUsb 中的类型参数。

// DD 类定义为 泛型类,则不需要确定 接口的类型参数
// 但 DD 类定义的类型参数必须要有接口中类型参数
class DD<U, R> implements IUsb<U, R> { ...
}

同理我们的接口继承接口也是一样的道理,也可以泛型接口继承泛型接口,规则跟上面一样,这里就不写代码了。

 泛型方法

 泛型方法的定义

当在一个方法签名中的返回值前面声明了一个 < T > 时,该方法就被声明为一个泛型方法。< T >表明该方法声明了一个类型参数 T,并且这个类型参数 T 只能在该方法中使用。当然,泛型方法中也可以使用泛型类定义的类型参数。 

public <类型参数> 返回类型 方法名(类型参数 变量名) {...
}

1.只有在方法中声明了< T >的方法才是泛型方法,仅使用了泛型类定义的类型参数的方法并不是泛型方法

2.泛型方法中可以同时声明多个类型参数。 

3.泛型方法中也可以使用泛型类中定义的泛型参数。

需要注意的是泛型类中定义的类型参数和泛型方法中定义的类型参数是相互独立的,它们一点关系都没有。

如果泛型方法和泛型类出现同名的类型参数,在泛型方法内部则优先选择泛型方法的类型参数。为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数最好不要同名

4.前面在泛型类的定义中提到,在静态成员中不能使用泛型类定义的类型参数,但我们可以将静态成员方法定义为一个泛型方法,自己内部去使用自己的类型参数。

public class Test2<T> {   // 泛型类定义的类型参数 T 不能在静态方法中使用// 但可以将静态方法声明为泛型方法,方法中便可以使用其声明的类型参数了public static <E> E show(E one) {     return null;    }    
}  

 泛型方法的使用

泛型类,在创建类的对象的时候确定类型参数的具体类型;
泛型方法,在调用方法的时候确定类型参数的具体类型。

当调用泛型方法时,根据外部传入的实际对象的数据类型,编译器就可以判断出类型参数所代表的具体数据类型。

public class Demo {  public static void main(String args[]) {  GenericMethod d = new GenericMethod(); // 创建 GenericMethod 对象  String str = d.fun("汤姆"); // 给GenericMethod中的泛型方法传递字符串  int i = d.fun(30);  // 给GenericMethod中的泛型方法传递数字,自动装箱  System.out.println(str); // 输出 汤姆System.out.println(i);  // 输出 30GenericMethod.show("Lin");// 输出: 静态泛型方法 Lin}  
}class GenericMethod {// 普通的泛型方法public <T> T fun(T t) { // 可以接收任意类型的数据  return t;} // 静态的泛型方法public static <E> void show(E one){     System.out.println("静态泛型方法 " + one);}
}  

泛型方法中的类型推断 

泛型方法中的类型推断是指编译器根据方法的参数类型来推断泛型类型参数的具体类型。

所以在调用泛型方法的时候,我们可以显式地指定类型参数,也可以不指定。

当泛型方法的形参列表中有多个类型参数时,在不指定类型参数的情况下,方法中声明的的类型参数为泛型方法中的几种类型参数的共同父类的最小级,直到 Object。

在指定了类型参数的时候,传入泛型方法中的实参的数据类型必须为指定数据类型或者其子类。

我们直接看实例更方便理解以上知识点:

public class Test {// 这是一个简单的泛型方法  public static <T> T add(T x, T y) {  return y;  }public static void main(String[] args) {  // 一、不显式地指定类型参数//(1)传入的两个实参都是int类型,经过编译器推断出类型为Integer,所以泛型方法中的<T>为<Integer>int i = Test.add(1, 2);//(2)传入的两个实参一个是 Integer,另一个是 Float,// 所以<T>取共同父类的最小级,<T> == <Number>Number f = Test.add(1, 1.2);// 传入的两个实参一个是 Integer,另一个是 String,// 所以<T>取共同父类的最小级,<T> == <Object>Object o = Test.add(1, "asd");// 二、显式地指定类型参数//(1)指定了<T> = <Integer>,所以传入的实参只能为 Integer 对象    int a = Test.<Integer>add(1, 2);//(2)指定了<T> = <Integer>,所以不能传入 Float 对象int b = Test.<Integer>add(1, 2.2);// 编译错误//(3)指定<T> = <Number>,所以可以传入 Number 对象// Integer 和 Float 都是 Number 的子类,因此可以传入两者的对象Number c = Test.<Number>add(1, 2.2); }  
}

 泛型的上界

泛型的上界定义是指在泛型类型参数声明时,通过使用extends关键字来限制该类型参数必须是某个特定类型或其子类型。这样可以确保在使用泛型时,只能传入符合上界要求的类型。 语法:<类型参数 extends 具体引用类型>

例如,假设我们有一个泛型类Box<T>,我们可以使用上界定义来限制T只能是Number类及其子类:

class Box<T extends Number> { private T value; public void setValue(T value) {this.value = value;} public T getValue() {return value; 
} } 

在上述代码中,T extends Number表示T必须是Number类或其子类。这样,在创建Box对象时,只能传入Number类及其子类的实例作为泛型参数。

所以这就是我们泛型的上界的  定义与使用。

而对于泛型既然有上界,那么肯定有下界,对于下界它在泛型的进阶中,我们打算数据结构结尾部分再讲泛型的进阶部分。 现在先把泛型的基础打牢再说。

总结 

所以以上就是泛型的初步认识(1),这部分的知识点比较简单,较容易理解。到了第二部分的泛型知识点,层面就比较深了,很晦涩难懂。所以第一部分的知识点还请大家认真消化吸收,下篇文章将带来泛型第二部分的讲解。还希望各位大佬们能给个三连,点点关注,点点赞,发发评论呀,感谢各位大佬~❤️❤️💕💕🥳🎉🎉🎉

 

 

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

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

相关文章

Java 算法篇-深入了解 BF 与 KMP 算法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 BF 算法概述 1.1 BF 算法实际使用 2.0 KMP 算法概述 2.1 KMP 算法实际使用 2.2 相比于 BF 算法实现&#xff0c;KMP 算法的重要思想 2.3 为什么要这样设计&#x…

listpack

目录 为什么有listpack? listpack结构 listpack的节点entry 长度length encoding编码方式 listpack的API 1.创建listpack 2.遍历操作 正向遍历 反向遍历 3.查找元素 4.插入/替换/删除元素 总结 为什么有listpack? ziplist是存储在连续内存空间&#xff0c;节省…

华为云服务镜像手动更换

操作步骤&#xff1a; 1、进入华为云首页点击云容器引擎CCE&#xff1b; 2、选择你所要更换镜像的环境【这里以dev环境演示】&#xff1b; 3、点击dev环境后选择顶部的命名空间&#xff0c;点击【工作负载】中右侧栏的【升级】按钮&#xff1b; 4、点【更换镜像】选择你在test…

C++之类和对象三

目录 拷贝构造函数 定义铺垫 浅拷贝 深拷贝 总结 拷贝构造函数 那在创建对象时&#xff0c;可否创建一个与一个对象一某一样的新对象呢&#xff1f; 定义铺垫 构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c…

顺丰同城急送API对接(附源码)

一、背景 最近公司让我对接顺丰同城急送的API&#xff0c;讲讲里面需要注意的几点 官方的API文档有些示例代码也不全&#xff0c;具体细节不多说&#xff0c;如果你现在也需要对接他们API&#xff0c;可以参考本篇博客再配合官方文档结合起来看&#xff0c;可以让您再开发的时…

期权小知识科普

期权的交易时间 上交所期权合约的交易时间为每个交易日9:15至9:25、9:30至11:30、13&#xff1a;00至15:00。 其中&#xff0c;9:15至9:25为开盘集合竞价时间&#xff0c;14:57-15:00为收盘集合竞价时间&#xff0c;其余时段为连续竞价时间&#xff0c;交易所规则另有规定的除…

Pytorch-自动微分模块

&#x1f947;接下来我们进入到Pytorch的自动微分模块torch.autograd~ 自动微分模块是PyTorch中用于实现张量自动求导的模块。PyTorch通过torch.autograd模块提供了自动微分的功能&#xff0c;这对于深度学习和优化问题至关重要&#xff0c;因为它可以自动计算梯度&#xff0c…

VUE-列表

VUE-列表 列表功能 如下例子 列表展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&qu…

CorelDRAW Graphics Suite2024最新永久免费版功能强大的图形设计软件

CorelDRAW Graphics Suite是一款功能强大的图形设计软件套件&#xff0c;它提供了丰富的绘图工具、编辑功能和设计资源&#xff0c;适用于从专业设计师到普通用户的广泛群体。以下是CorelDRAW Graphics Suite的一些主要功能特点&#xff1a; 矢量图形设计&#xff1a;CorelDRAW…

Jenkins 流水线多阶段构建

Jenkins流水线配置遇到 无法识别的。需要使用 自定义环境 项。 比如官网的在流水线中使用Docker Started by remote host 172.17.0.1 Obtained Jenkinsfile from git http://10.99.20.51:8082/root/java-devops-demo.git org.codehaus.groovy.control.MultipleCompilationErro…

智慧化赋能园区新未来:探讨智慧园区如何以科技创新为引擎,推动产业转型升级

随着科技的飞速发展&#xff0c;智慧化已成为推动园区产业升级和转型的重要引擎。智慧园区&#xff0c;以其高效、便捷、智能的特性&#xff0c;正逐步改变传统的产业园区模式&#xff0c;为产业发展注入新的活力。本文旨在探讨智慧园区如何以科技创新为引擎&#xff0c;推动产…

制作适用于openstack平台的win10镜像

1. 安装准备 从MSDN下载windows 10的镜像虚拟机开启CPU虚拟化的功能。从Fedora 网站下载已签名的 VirtIO 驱动程序 ISO 。 创建15 GB 的 qcow2 镜像&#xff1a;qemu-img create -f qcow2 win10.qcow2 15G 安装必要的软件 yum install qemu-kvm qemu-img virt-manager libvir…

GaN HEMT中短沟道效应的建模

来源&#xff1a;Modeling of Short-Channel Effects in GaN HEMTs&#xff08;TED 20年&#xff09; 摘要 在本文中&#xff0c;我们提出了一种用于估算GaN高电子迁移率晶体管&#xff08;HEMT&#xff09;器件中短沟道效应&#xff08;SCEs&#xff09;的显式和解析的基于电…

【创建型模式】单例模式

一、单例模式概述 单例模式的定义&#xff1a;又叫单件模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。&#xff08;对象创建型&#xff09; 要点&#xff1a; 1.某个类只能有一个实例&#xff1b;2.必须自行创建这个实例&#xff1b;3.必须自行向整…

固体矿产资源储量分类GBT17766-2020

1999分类标准采用三轴体系划分资源量与处理&#xff0c;表达复杂、经济意义划分过细、实用性不强 虽然不再采用”三轴“表达方式&#xff0c;但依然考虑地质可靠程度、经济意义、可行性评价 矿产资源勘查&#xff1a;通常依靠地球科学知识&#xff0c;运用地质填图&#xff0…

python语言零基础入门——变量与简单数据类型

目录 一、变量 1.创建变量 2.变量的修改 3.变量的命名 &#xff08;1&#xff09;常量 &#xff08;2&#xff09;标识符 &#xff08;3&#xff09;关键字 &#xff08;4&#xff09;命名规则 二、简单数据类型 1.变量的数据类型 2.数据类型 3.整型&#xff08;In…

软考-系统集成项目管理中级--项目人力资源管理(输入输出很重要!!!本章包含案例题,着重复习)

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 1、人力资源管理的过程:(掌握) (1)项目人力资源计划编制:确定与识别项目中的角色、分配项目职责和汇报关系&#xff0c;并记录下来形成书面文件&#xff0c;其中也包括项目人员配备管理计划。…

C语言进阶课程学习记录-第39课 - 程序中的3个基本数据区

C语言进阶课程学习记录-第39课 - 程序中的3个基本数据区 栈实验-栈空间释放后数据无效堆静态存储区实验-静态变量和全局变量小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 栈 实验-栈空间释放后数据…

吴恩达机器学习笔记:第 8 周-13 聚类(Clustering)13.1-13.2

目录 第 8 周 13、 聚类(Clustering)13.1 无监督学习&#xff1a;简介 第 8 周 13、 聚类(Clustering) 13.1 无监督学习&#xff1a;简介 在这个视频中&#xff0c;我将开始介绍聚类算法。这将是一个激动人心的时刻&#xff0c;因为这是我们学习的第一个非监督学习算法。我们…

Day3 权限管理

Day3 权限管理 这里会总结构建项目过程中遇到的问题&#xff0c;以及一些个人思考&#xff01;&#xff01; 学习方法&#xff1a; 1 github源码 文档 官网 2 内容复现 &#xff0c;实际操作 项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目 创建管理员…