泛型的初步认识(1)

news2024/11/17 15:45:44

前言~🥳🎉🎉🎉   

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 {
    @Override
    public Double get(String s) {
        return null;
    }
    @Override
    public void hi(Double d) {
		...
    }
}

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

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

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

// 实现泛型接口时没有确定类型参数,则默认为 Object
// 建议直接写成 IUsb<Object, Object>
class CC implements IUsb {//等价 class CC implements IUsb<Object, Object> 
    @Override
    public Object get(Object o) {
        return null;
    }
    @Override
    public 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);  // 输出 30

	GenericMethod.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.coloradmin.cn/o/1615097.html

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

相关文章

Unity中的UI系统之UGUI

目录 概述UGUI基础——六大基础组件六大基础组件概述Canvas画布组件CanvasScaler画布缩放控制器组件必备知识恒定像素模式缩放模式恒定物理模式3D模式 Graphic Raycaster图形射线投射器EventSystem和Standalone Input ModuleRectTransform UGUI基础——三大基础控件Image图像控…

【解决】Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed

问题原因&#xff1a; 在Java8及高版本以上的版本在源应用程序不信任目标应用程序的证书&#xff0c;因为在源应用程序的JVM信任库中找不到该证书或证书链。也就是目标站点启用了HTTPS 而缺少安全证书时出现的异常 解决方案&#xff1a; 我使用的是忽略证书验证 public clas…

vs code server for wsl closed unexpectedly

前言&#xff1a; 我的Windows 版本&#xff1a; 10.0.19045.4291 &#xff08;如果你是Win11或者你要使用WSL2请谨慎&#xff09; 之前是可以用的&#xff0c;但安装Vmware&#xff08;并安装了Ubuntu进行了一番实验后&#xff0c;就出现如标题所述问题&#xff09; 问题&a…

内存满了如何处理?

目录 虚拟内存 内存分配过程 直接内存回收和后台内存回收 回收内存的触发标准 那些内存被回收呢? 内存回收后,内存还是不够怎么办呢? 虚拟内存 介绍操作系统内存如何使用时,不可以避免的先认识到虚拟内存 首先我们通过虚拟内存的作用,来认识一下: 1.虚拟内存可以使得…

基础SQL DML-插入语句

插入语句前&#xff0c;我们先创建一个表。表的创建在DDL语句里面涉及&#xff0c;可以参考&#xff1a;小赖同学吖-CSDN博客 我们创建一个员工表进行数据的插入操作 插入&#xff08;添加&#xff09;语句的语法 给员工表添加一条记录 给员工表添加多条记录 也可以通过下面的方…

Python 面向对象——2.类与对象实例属性补充解释,self的作用等

本章学习链接如下&#xff1a; Python 面向对象——1.基本概念 实例的属性 1.创建对象 在上一小节的学习中我们提到了类中的变量与函数变量的区别&#xff0c;self.param1和param1&#xff0c;接下来我们继续详细解释这个知识点。 当我们创建一个学生的类&#xff0c;比如…

铜缆与网线:数字时代的信息高速公路

在现代社会&#xff0c;信息传输已成为日常生活的重要部分。从个人通信到全球数据中心&#xff0c;铜缆和网线扮演着至关重要的角色。本文将详细介绍铜缆和网线的类型、特点以及它们在数字时代的应用。 铜缆的种类与应用 铜缆的类型 UTP&#xff08;无屏蔽双绞线&#xff09;&…

登录的几种方式

一、session 1、客户端发送请求&#xff0c;服务器将登录信息存储在 Session 中&#xff0c;Session 依赖于 Cookie&#xff08;cookie指的就是在浏览器里面存储的一种数据&#xff0c;仅仅是浏览器实现的一种数据存储功能。Cookie实际上是一小段的文本信息。&#xff09;&…

Arthas介绍及使用技巧

文章目录 简介能做什么&#xff1f; 使用下载并启动arthas选择应用 java 进程退出 arthas 常用查看命令帮助查看 dashboard通过 thread 命令来获取到线程的栈通过 jad 来反编译 Classwatch 查看方法出入参、sc 搜索类: 查看已加载类所在的包monitor 方法执行监控trace 方法内调…

牛客NC238 加起来和为目标值的组合【中等 DFS C++、Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/172e6420abf84c11840ed6b36a48f8cd 思路 本题是组合问题&#xff0c;相同元素不同排列仍然看作一个结果。 穷经所有的可能子集&#xff0c;若和等于target&#xff0c;加入最终结果集合。 给nums排序是为了方便…

day04 51单片机-矩阵按键

1 矩阵按键 1.1 需求描述 本案例实现以下功能:按下矩阵按键SW5到SW20,数码管会显示对应的按键编号。 1.2 硬件设计 1.2.1 硬件原理图 1.2.2 矩阵按键原理 1.3软件设计 1)Int_MatrixKeyboard.h 在项目的Int目录下创建Int_MatrixKeyboard.h,写入以下内容。 #ifndef __…

Pyhton Sqlite3手机数据库

代码结果 Code import sqlite3 connsqlite3.connect(test.db) csconn.cursor() create_tb_sqlcreate table if not exists info(id int primary key,name text,age int)cs.execute(create_tb_sql)# cs.execute(insert into info(id,name,age) values(3,"dog_Senior&quo…

Ubuntu Server 20.04 LTS 64bit安装ftp服务

1.安装vsftpd sudo apt install vsftpd2.配置vsftpd sudo vim /etc/vsftpd.conf write_enableYES # 启用任何形式的FTP写入命令&#xff0c;即可以修改文件local_umask022 # 本地用户创建文件的 umask 值&#xff0c;默认是被注释的connect_from_port_20YES # 针对 PORT 类型…

java 溯本求源之基础(十八)之Monitoring--jmc

1.JMC概述 JMC全称Java Mission Control&#xff0c;集成了多个功能强大的组件&#xff0c;其中最核心的两部分是管理控制台和Java Flight Recorder。管理控制台允许开发者实时监控应用的运行状态&#xff0c;捕捉各种性能指标&#xff1b;而Java Flight Recorder则提供了一种高…

深兰科技入选2024全国“人工智能+”行动创新案例TOP100

近日&#xff0c;中科院《互联网周刊》联合eNET研究院、德本咨询、中国社会科学院信息化研究中心共同发布了《2024全国“人工智能”行动创新案例TOP100》榜单。经评委会层层遴选&#xff0c;深兰科技专为洛阳市打造的“工业智能化洛阳中心”项目成功入围该榜单。一同入围的还包…

力扣(leetcode) 407. 接雨水 II 3D接雨水

力扣(leetcode) 407. 接雨水 II 3D接雨水 给你一个 m x n 的矩阵&#xff0c;其中的值均为非负整数&#xff0c;代表二维高度图每个单元的高度&#xff0c;请计算图中形状最多能接多少体积的雨水。 示例 1: 输入: heightMap [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] 输…

IEC104协议

1. 简介 IEC104规约是一个广泛应用于电力、城市轨道交通等行业的国际标准。 2. 术语解释 遥脉 (电度量)&#xff1a; 是指对现场某装置所发出的脉冲信号进行周期累计的一种远程计数操作。 其实&#xff0c;遥脉也可以看成是被具体规定了采用脉冲计数作为测量方法的一种遥测…

日本二次元团建国内院线:一周一部,占据36.2%票房

从《你想活出怎样的人生》开始&#xff0c;到《哈尔的移动城堡》结束&#xff0c;日本动画正在占据国内院线的整个4月份档期。 包括《数码宝贝02&#xff1a;最初的召唤》、《间谍过家家 代号&#xff1a;白》多部作品在内&#xff0c;整个国内四月份院线日本动画平均一周上映…

分布式锁(Redis)

一、序言 本文和大家聊聊分布式锁以及常见的解决方案。 二、什么是分布式锁 假设一个场景&#xff1a;一个库存服务部署在上面三台机器上&#xff0c;数据库里有 100 件库存&#xff0c;现有 300 个客户同时下单。并且这 300 个客户均摊到上面的三台机器上&#xff08;即三台…

4套java智慧型管理系统源码-智慧校园-智慧工地-智慧城管-智慧3D导诊

第一套&#xff1a;Java智慧校园系统源码 智慧学校源码 微信小程序电子班牌 智慧校园系统简介&#xff1a; 智慧校园的建设逐渐被师生、家长认可接受&#xff0c;智慧校园通过对在校师生、教务等所有人员的信息以及各种信息搜集与储存&#xff0c;进行数据优化与管理&#xf…