【java基础】泛型程序设计基础

news2024/9/19 15:12:40

文章目录

  • 泛型是什么
  • 自定义泛型类
  • 自定义泛型方法
  • 类型变量的限定
  • 总结

泛型是什么

泛型类和泛型方法有类型参数,这使得它们可以准确地描述用特定类型实例化时会发生什么。在没有泛型类之前,程序员必须使用Objct编写适用于多种类型的代码。这很烦琐,也很不安全。

随着泛型的引入,Java有了一个表述能力很强的类型系统,允许设计者详细地描述变量和方法的类型要如何变化。

泛型程序设计(generic programming)意味着编写的代码可以对多种不同类型的对象重用。

下面的代码就是没有使用泛型的集合

        // 该集合我想要存放int类型的数据
        List list = new ArrayList();
        list.add(100); // 加入int
        list.add("hello"); // 放入字符串
        list.add(true); // 放入布尔类型

        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i); // 获取到的值是Object
            int k = (Integer) o; // 强制转换
            System.out.println(k);
        }

可以发现上面的代码在集合中什么都能放入,并没有进行类型检查。而且在获取集合元素的时候返回的是Object,我们还要进行强转。运行看看一下,结果如下

在这里插入图片描述

可以发现报错了,这就是因为在集合里面存放了其他类型的数据。集合不使用泛型那么就是存储的Object数据,我们将其转换为Integer所以就出现了ClassCastException。现在就已经可以发现java的弊端了,没有一个参数检查机制,代码极不安全,泛型就是用来弥补这点的。看下面泛型代码。

        List<Integer> list = new ArrayList<>();
        list.add(100);
        // list.add("hello") // 类型检查,编译都不能通过
        // list.add(true) // 编译不能通过

        for (int i = 0; i < list.size(); i++) {
            Integer k = list.get(i); // 返回的直接就是Integer
            System.out.println(k);
        }

我们可以在<>里面指定要存储的元素类型,这就是泛型,使用泛型后在往集合添加元素的时候就会进行检查,如果不是指定的元素,那么就会出现编译错误,程序编译都不能通过。使用泛型后,集合返回的就直接是指定的类型,也就不需要强转类型转换了。

通过上面的代码,大家应该初步体会到了泛型的好处和强大,下面就来学习如何自定义泛型类和泛型方法

自定义泛型类

泛型类就是有一个或多个类型变量的类。下面我就通过MyTool这个类来进行说明

public class MyTool<T> {
    private T info;

    public MyTool(T info) {
        this.info = info;
    }

    public T getInfo() {
        return info;
    }
}

上面的MyTool这个类就是一个泛型类,在这个类中引入了一个类型变量T,用尖括号(<>)括起来的,放在类名后面。这个T就是我们在创建对象的时候指定的。

MyTool<String> myTool = new MyTool<>("这是自定义泛型类");

我们在尖括号(<>)里面写的类型就会成为T的类型,这里<>里面写的类型为String,那么T就是代表String。

对于 new MyTool<>(“这是自定义泛型类”) 这部分代码,我们在构造器中传入了一个字符串,原因就是T代表的是字符串,而我们的构造器中要传入的内容就是T,也就是字符串,没有问题。

对于在上面的MyTool类,由于我们指定的T为String,所以可以将其理解为就是一个普通类,如下

public class MyTool {
    private String info;

    public MyTool(String info) {
        this.info = info;
    }

    public String getInfo() {
        return info;
    }
}

现在,对于泛型类的基本使用基本就说完了,我们自定义泛型类就是在类后面加上<>,在这里面写上类型变量,然后再类中使用这个类型变量即可。对于类型变量,我们一般都是使用大写字母,而且很简短,在Java库使用变量E表示集合的元素类型,K和V分别表示表的键和值的类型。T(必要时还可以用相邻的字母U和S)表示“任意类型”。
注意:对于类型变量并不是一定为一个大小字母,只不过是约定俗成罢了,例如,下面代码也是正确的

public class TypeParameter<AAAAA> {
    private AAAAA aaaaa;
}

但是还是建议大家就写为一个大写字母,遵顼java规范。

对于泛型类,我们在<>里面可以写上多个类型变量,使用逗号分隔,例如下面代码

public class MulTypeParam<K,V> {
}

这样定义以后,我们在使用这个对象就要在<>里面传入2个变量

MulTypeParam<Integer, String> typeParam = new MulTypeParam<>();

这样写的话,那么K就代表Integer类型,V就代表String类型

自定义泛型方法

上面说的是自定义泛型类,现在来讲一下泛型方法。下面就是一个简单示例

public class SimpleGenericMethod {

    public static <T> T getMiddleInfo(T... ts) {
        int index = ts.length / 2;
        return ts[index];
    }
}

对于泛型方法,我们并不需要放在泛型类中,放在普通类中也没有问题。对于泛型方法,我们将类型变量放在<>中,<>放在返回值前面,修饰符后面。

上面的方法就是接收T类型的参数,然后返回一个T。下面就是对泛型方法的调用

String middleInfo = SimpleGenericMethod.<String>getMiddleInfo("java", "python", "c", "c++", "php");

可以发现在泛型方法中,我们是在方法前面添加了一个<>,然后指定了类型。但是对于大多数情况下,<>都可以省略,编译器会根据传入的参数推断出类型。
在几乎所有情况下,泛型方法的类型推导都可以正常工作。下面写法就是省略<>写法

String middleInfo = SimpleGenericMethod.getMiddleInfo("java", "python", "c", "c++", "php");

类型推导的原则就是寻找参数的公共父类。

对于泛型方法,我们也可以在<>里面定义多个类型变量

    public static <X, Y> Y towTypeParam(X x, Y y) {
        return y;
    }

上面代码就表示传入一个X类型的变量和一个Y类型的变量,然后返回一个Y类型变量。

类型变量的限定

在很多的情况下,我们使用泛型时,并不是上面类型的参数都能传入,而是有所现在,比如是某个类的子类,或者必须实现某个接口。下面就来说明如何完成这些对泛型的限制。

先来看一个例子

public interface Eat {
    
    void eat();
}
public class TypeParamRestrict {

    public static <T> void eats(T... ts) {
        for (T t : ts) {
            ((Eat) t).eat();
        }
    }
}

看看上面这个eats有上面问题呢?可以发现,我们并没有检查T类型的参数,T不一定是一个实现接口的Eat的对象,这样调用就会出错,所以,我们应该对T进行限制,写法如下

public class TypeParamRestrict {

    public static <T extends Eat> void eats(T... ts) {
        for (T t : ts) {
            t.eat();
        }
    }
}

T extends Eat就表示传入的类型必须是为Eat,或者Eat的子类。这里使用extends可能有人很疑惑,Eat不是接口吗?为什么是使用extends,事实上,这里选择extends是为了更接近子类的概念,对于接口和类都是使用extends。使用了限定符后,就不需要进行类型转换了,T已经是Eat的子类,所以可以直接掉用eat方法。

上面这样写了以后,再调用eats这个方法,参数就必须是实现Eat接口的类。

对于一个类型变量,我们还可以有多个限定,例如下面代码

<T extends Eat & Serializable>

使用&就表示必须且的意思,表示T要同时实现Eat和Serializable接口。
注意:对于限定,可以有多个接口,但是只能有一个是类,而且必须写为第一个限定。为什么只能有一个限定类,因为java是单继承的。类型变量不可能同时实现多个类

总结

泛型程序设计(generic programming)就是意味着编写的代码可以对多种不同类型的对象重用。

关于泛型的更多知识,参考以下内容

泛型程序设计基础
类型擦除、桥方法、泛型代码和虚拟机
泛型的限制及其继承规则
泛型的通配符(extends,super,?)

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

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

相关文章

Tuxera NTFS2023MacOS读写软件功能介绍使用

当我们遇到磁盘不能正常使用的情况时本能的会以为是磁盘损坏了&#xff0c;但某些情况下却并非如此。对于mac操作系统来说&#xff0c;软件无法使用设备无法正常读写似乎是很常见的事&#xff0c;毕竟现在的mac电脑对PC机上的产品无法完全适应使用&#xff0c;经常会存在兼容方…

Leetecode 661. 图片平滑器

图像平滑器 是大小为 3 x 3 的过滤器&#xff0c;用于对图像的每个单元格平滑处理&#xff0c;平滑处理后单元格的值为该单元格的平均灰度。 每个单元格的 平均灰度 定义为&#xff1a;该单元格自身及其周围的 8 个单元格的平均值&#xff0c;结果需向下取整。&#xff08;即&…

Java之可变参数

目录 一.可变参数的引入 1.问题引入 2.可变参数的使用 二.可变参数的注意点 1.可变参数只能定义一个 2.可变参数必须是函数参数的最后一个​编辑 一.可变参数的引入 1.问题引入 当我们需要定义一个方法sum,接受任意个整型变量,结果返回这些整型变量的和. 我们没有学习可…

SCAFFOLD: Stochastic Controlled Averaging for Federated Learning学习

SCAFFOLD: Stochastic Controlled Averaging for Federated Learning学习背景贡献论文思想算法局部更新方式全局更新方式实验总结背景 传统的联邦学习在数据异构(non-iid)的场景中很容易产生“客户漂移”(client-drift )的现象&#xff0c;这会导致系统的收敛不稳定或者缓慢。…

nacos的介绍和下载安装(详细)

目录 一、介绍 1.什么是nacos&#xff08;含有官方文档&#xff09;&#xff1f; 2.nacos的作用是什么&#xff1f; 3.什么是nacos注册中心&#xff1f; 4.核心功能 二、下载安装 一、介绍 1.什么是nacos&#xff08;含有官方文档&#xff09;&#xff1f; 一个更易于…

libGDX:灯光效果实现一(实现一个点光源)

国内的libGDX文章很少&#xff0c;特别是libGDX实现灯光效果&#xff0c;所以就开始总结灯光效果的实现 绿色的框 是为了方便看到Body位置&#xff0c;使用Box2DDebugRenderer渲染的 工欲善其事&#xff0c;必先利其器&#xff0c;工具集合 gdx-setup.jar 1. 从libGDX官网下载…

GrabCut算法、物体显著性检测

图割GraphCus算法。利用颜色、纹理等信息对GraphCut进行改进&#xff0c;形成效果更好的GrabCut算法。 对图像的目标物体和背景建立一个K维的全协方差高斯混合模型。 其中&#xff0c;单高斯模型的概率密度函数用公式表示为&#xff1a; 高斯混合模型可表示为n个单高斯模型的概…

Java生态/Redis中如何使用Lua脚本

文章目录一、安装LUA1&#xff09;简单使用二、lua语法简介1、注释1&#xff09;单行注释2&#xff09;多行注释2、关键字3、变量1&#xff09;全局变量2&#xff09;局部变量4、数据类型1&#xff09;Lua数组2&#xff09;字符串操作5、if-else6、循环1&#xff09;for循环1&g…

Java多线程中的CAS

多线程中的CAS 什么是CAS CAS CompareAndSwap&#xff0c;或者 CompareAndSet&#xff0c; 是一个能够比较和替换的方法。 这个方法能够在多线程环境下保证对一个共享变量进行修改时的原子性不变。 通常&#xff0c;CAS方法会传递三个参数&#xff0c; ● 第一个参数V表示要更新…

核心 Android 调节音量的过程

核心 Android 系统提供的调节音量的方法 核心 Android 系统提供了多种调节音量的方法&#xff0c;这些方法主要包括如下这些。 如在 Android Automotive 调节音量的过程 中我们看到的&#xff0c;CarAudioService 最终在 CarAudioDeviceInfo 中 (packages/services/Car/servi…

RHCSA-文件内容显示(3.6)

查看命令 cat&#xff1a;显示文件内容 cat -n&#xff1a;显示文件内容的同时显示编号 tac&#xff1a;倒叙查看 head 文件名 &#xff08;默认显示前10行&#xff09;&#xff1a;显示前10行 tail&#xff1a;显示末尾行数信息 more&#xff1a;查看文件信息&#xff0c;从头…

前端基础知识

文章目录前端基础知识HTML1. html基本结构2.常见的html标签注释标签标题标签(h1~h6)段落标签p换行标签 br格式化标签图片标签&#xff1a;img超链接标签表格标签列表标签表单标签input标签label标签select标签textarea 标签盒子标签div&span3. html特殊字符CSS1. 基本语法2…

Hive总结

文章目录一、Hive基本概念二、Hive数据类型三、DDL,DML,DQL1 DDL操作2 DML操作3 DQL操作四、分区操作和分桶操作1、分区操作2、分桶操作五、Hive函数六、文件格式和压缩格式一、Hive基本概念 Hive是什么&#xff1f; Hive&#xff1a;由 Facebook 开源用于解决海量结构化日志的…

监控易网络管理:网络流量分析

1、什么是网络流量分析2、网络流量分析的作用3、为什么要用网络流量分析功能&#xff0c;如何开启什么是网络流量分析简单的来说&#xff0c;网络流量分析就是捕捉网络中流动的数据包&#xff0c;并通过查看包内部数据以及进行相关的协议、流量、分析、统计等&#xff0c;协助发…

[ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

XSS挑战赛(xsslabs)1~10关通关解析

简介 XSS挑战赛&#xff0c;里面包含了各种XSS的防御方式和绕过方式&#xff0c;好好掌握里面的绕过细节&#xff0c;有助于我们更好的去发现XSS漏洞以及XSS的防御。本文更多的是分享解析的细节&#xff0c;不是一个标准的答案&#xff0c;希望大家在渗透的时候有更多的思维。…

基于MindAR实现的网页端WebAR图片识别叠加动作模型追踪功能(含源码)

前言 由于之前一直在做这个AR/VR 相关的功能开发&#xff0c;大部分的时候实现方式都是基于高通Vuforia或者EasyAR等基于Unity3d的引擎的开发&#xff0c;这样开发的程序大部分都是运行在APP上&#xff0c;安卓或者ios的开发也能一次性搞定。不过当时大部分的需求都是需要在网…

Xshell的下载、使用、配置【ssh、telnet、串口】

目录 一、概述 二、Xshell的使用  2.1 Xshell使用ssh协议远程连接Linux主机或服务器  2.2 Xshell使用telnet协议远程连接Linux开发板  2.3 Xshell使用SERIAL协议远程连接Linux开发板 三、Xshell常用配置  3.1 配置默认会话属性 一、概述 Xshell是由NetSarang公司开发的强大…

【Linux】-- 进程间通讯

目录 进程间通讯概念的引入 意义&#xff08;手段&#xff09; 思维构建 进程间通信方式 管道 站在用户角度-浅度理解管道 匿名管道 pipe函数 站在文件描述符角度-深度理解管道 管道的特点总结 管道的拓展 单机版的负载均衡 匿名管道读写规则 命名管道 前言 原理…

深入理解java虚拟机精华总结:性能监控和故障处理工具、类加载机制

深入理解java虚拟机精华总结&#xff1a;性能监控和故障处理工具、类加载机制性能监控和故障处理工具、类加载机制jpsjstatjinfojmapjhatjstackVisualVM类加载机制类加载的时机类加载的过程加载验证准备解析初始化类加载器类与类加载器双亲委派模型破坏双亲委派模型往期内容&am…