Java从入门到放弃 之 泛型

Java从入门到放弃 - 泛型

  • 引入泛型的背景
    • 怎么解决这个问题?
      • 解决方式一
      • 解决方式二
    • 使用泛型
      • 代码案例一
      • 代码案例二
    • 通配符的使用
      • extends 通配符
      • super 通配符
      • 对比extends和super通配符
    • 泛型的原理

引入泛型的背景

在Java中当我们使用容器存储元素的时候(建议先了解一部分Java容器知识),实际上使用的是Object存储的元素,比如下面ArrayList部分源码

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {private static final long serialVersionUID = 8683452581122892189L;private static final int DEFAULT_CAPACITY = 10;private static final Object[] EMPTY_ELEMENTDATA = new Object[0];private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];transient Object[] elementData;private int size;
}

从这部分源码我们可以看出ArrayList使用的是Object[] 数组存储的元素,但是这里就引出了一个问题。我们使用Object存储,是不是就把原始类型就给丢弃了。导致我们在从容器中拿出元素之后,想要进一步使用元素还需要向下转型,这让代码变得麻烦、臃肿、不安全,并且容易发生类型转换异常。

怎么解决这个问题?

因为存储的时候是通用的容器,用Object没有问题,但是使用的时候我们还是需要知道原始类型。

解决方式一

使用特定容器不用通用容器不就好了, 比如存储String我们就写一个存储String数组的ArrayList,存储Integer 就写一个存储Integer数组的ArrayList

public class StringArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {private static final long serialVersionUID = 8683452581122892189L;private static final int DEFAULT_CAPACITY = 10;private static final String[] EMPTY_ELEMENTDATA = new Object[0];private static final String[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];transient String[] elementData;private int size;
}
public class IntegerArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {private static final long serialVersionUID = 8683452581122892189L;private static final int DEFAULT_CAPACITY = 10;private static final Integer[] EMPTY_ELEMENTDATA = new Object[0];private static final Integer[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];transient Integer[] elementData;private int size;
}

这样可不可以呢? 当然是可以的,但是有没有问题? 聪明的你,看上面的代码一下子就看出来了,这样写,会产生一大堆重复代码,而且还要写一大堆类。 这肯定不是一种很好的实现方式。

所以有没有更好的实现方式呢?

解决方式二

Java是强类型编程语言,强类型的意思就是在编写代码的时候必须要明确变量的类型,不然的话编译不通过。但是有时候我们不知道某些变量的具体类型是什么,只能用公共父类Object类型,这就是容器或者上面代码ArrayList里面为啥使用Object[]数组存储元素,因为我们不知道具体要存储的数据类型。其实观察上面两段代码,我们其实发现大部分都是相同的,只有标记用什么类型存储数组的地方是不一样的。解决这个问题的方式就是我们在程序的某个地方标识完全未知的类型,使程序顺利通过编译,等到使用的时候确定具体类型。 泛型(Generics)就是泛化的类型,即使用 表示一个暂时没有确定的类型。

使用泛型

接下我们就通过实际代码了解如何使用泛型

代码案例一

        public class Pair<T> {T first;T second;public Pair(T first, T second){this.first = first;this.second = second;}public T getFirst() {return first;}public T getSecond() {return second;}}
        Pair<Integer> minmax = new Pair<Integer>(1,1);Integer min = minmax.getFirst();Integer max = minmax.getSecond();

通过使用泛型,我们达到了使得Pair类的代码和它处理的数据类型不是绑定的,具体类型可以变化。也就是说Pair类即可以处理Integer也可以处理String等等

代码案例二

类型参数还可以是多个

        public class Pair<K, V> {K first;V second;public Pair(K first, V second){this.first = first;this.second = second;}public K getFirst() {return first;}public V getSecond() {return second;}}
        Pair<Integer, String> test = new Pair<Integer, String>(1,"test");Integer num = test.getFirst();String test = mintest.getSecond();

Pair<Integer, String> test = new Pair<>(1,“test”) 这样写,因为编译器可以自动推断泛型类型

通配符的使用

ArrayList 不是 ArrayList的父类, 你可以这样理解。 动物类是人类的父类, 装动物类的汽车类不是装人类的汽车类的父类。

extends 通配符

        public void addAll(ArrayList<Number> array) {}

对于这个把所有Number的list放到一个其他容器的方法,Integer是number的子类,Number能放的 Integer也可以放进去。但是上面我们说的继承关系可以知道。ArrayList 跟ArrayList 没有父子关系,直接把ArrayList 传入这个方法,会报错的。
怎么办? 这时候可以使用extends关键字

        public void addAll(ArrayList< ? extends Number> array) {}

这样使得方法接收所有泛型类型为Number或Number子类的ArrayList类型了,这样就解决了我们的问题。

super 通配符

ArrayList<? super Integer>表示,方法参数接受所有泛型类型为Integer或Integer父类的ArrayList类型。

对比extends和super通配符

  • <? extends T>允许调用读方法T get()获取T的引用,但不允许调用写方法set(T)传入T的引用(传入null除外);
  • <? super T>允许调用写方法set(T)传入T的引用,但不允许调用读方法T get()获取T的引用(获取Object除外)。

一个是允许读不允许写,另一个是允许写不允许读。

泛型的原理

这个是我们写的泛型类,编译器看到的就是我们写的源代码,就是下面这个案例写的这样,

        public class Pair<T> {T first;T second;public Pair(T first, T second){this.first = first;this.second = second;}public T getFirst() {return first;}public T getSecond() {return second;}}

实际上JVM执行的时候看到的代码是,

        public class Pair<T> {Object first;Object second;public Pair(Object  first, Object  second){this.first = first;this.second = second;}public Object  getFirst() {return first;}public Object  getSecond() {return second;}}

使用泛型的地方,编译器看到的源码,

        Pair<Integer> minmax = new Pair<Integer>(1,1);Integer min = minmax.getFirst();Integer max = minmax.getSecond();

这段代码实际上JVM看到的是

        Pair minmax = new Pair(1,1);Integer min = (Integer)minmax.getFirst();Integer max = (Integer)minmax.getSecond();

所以Java是通过擦除法实现泛型

  • 编译器会把 类似泛型地方的写法都会写成Object
  • 编译器根据 实现安全的类型转换

所以实际上Java的泛型是由编译器在编译时实行的,编译器泛型视为Object处理,在需要转型的时候,编译器会根据T的类型自动为我们实行安全地强制转型。

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

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

相关文章

Flutter-Web首次加载时添加动画

前言 现在web上线后首次加载会很慢&#xff0c;要5秒以上&#xff0c;并且在加载的过程中界面是白屏。因此想在白屏的时候放一个加载动画 实现步骤 1.找到web/index.html文件 2.添加以下<style>标签内容到<head>标签中 <style>.loading {display: flex;…

动态规划子数组系列一>最长湍流子数组

1.题目&#xff1a; 解析&#xff1a; 代码&#xff1a; public int maxTurbulenceSize(int[] arr) {int n arr.length;int[] f new int[n];int[] g new int[n];for(int i 0; i < n; i)f[i] g[i] 1;int ret 1;for(int i 1; i < n-1; i,m. l.kmddsfsdafsd){int…

win10 禁止更新

一、winR 输入 regedit 二、输入注册列表路径&#xff1a; &#xff08;1&#xff09;计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings &#xff08;2&#xff09;按照格式&#xff0c;创建文件命名: FlightSettingsMaxPauseDays &#xff08;3&…

【FAQ】HarmonyOS SDK 闭源开放能力 —ArkUI

1.问题描述&#xff1a; App启动的时候会有个弹框&#xff0c;询问用户是否需要进去隐私模式&#xff0c;在该隐私模式下&#xff0c;App不能获取任何用户信息。当前鸿蒙App级别是否有隐私模式&#xff1f; 解决方案&#xff1a; 当前实现隐私模式都是三方应用自己实现&…

传奇996_36——背包图标,物品位置问题

绑定位置不对位 CTRLF9背包物品文件&#xff0c;也就是bag_item文件夹的bag_item.lua文件&#xff0c;这个小框和大框的相对位置会影响那个绑定图标,就是背包物品组合的标签和下面子标签的相对位置 背包物品偏移到看不见 原因&#xff1a;CTRLF9背包物品文件&#xff0c;也就…

pyqt6、pyside6加载ui方法及路径总结

pyqt6、pyside6加载ui方法及路径总结 说明一、加载ui二、路径 说明 本教程适用于python3.11.X&#xff0c;pyqt6、pyside6.加载ui在一个项目中根目录及子目录的运用 一、加载ui pyqt6加载ui from PyQt6 import uic uic.loadUi(ui路径[str])#代码中添加加入这个代码就能加载…

springboot3如何集成knife4j 4.x版本及如何进行API注解

1. 什么是Knife4j knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案, 取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍!knife4j的前身是swagger-bootstrap-ui,swagger-bootstrap-ui自1.9.6版本后,正式更名为knife4j为了契合微服务的架构发展,由于原来…

中国电信星辰大模型:软件工厂与文生视频技术的深度解析

在科技日新月异的今天,人工智能(AI)技术正以惊人的速度改变着我们的生活和工作方式。作为这一领域的领军企业之一,中国电信凭借其强大的研发实力和深厚的技术积累,推出了星辰大模型,旨在为用户带来更加智能、高效、便捷的服务体验。本文将重点介绍中国电信星辰大模型中的…

机械设计学习资料

免费送大家学习资源&#xff0c;已整理好&#xff0c;仅供学习 下载网址&#xff1a; https://www.zzhlszk.com/?qZ02-%E6%9C%BA%E6%A2%B0%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83SOP.zip

【大数据学习 | Spark-Core】RDD的概念与Spark任务的执行流程

1. RDD的设计背景 在实际应用中&#xff0c;存在许多迭代式计算&#xff0c;这些应用场景的共同之处是&#xff0c;不同计算阶段之间会重用中间结果&#xff0c;即一个阶段的输出结果会作为下一个阶段的输入。但是&#xff0c;目前的MapReduce框架都是把中间结果写入到HDFS中&…

Flume日志采集系统的部署,实现flume负载均衡,flume故障恢复

目录 安装包 flume的部署 负载均衡测试 故障恢复 安装包 在这里给大家准备好了flume的安装包 通过网盘分享的文件&#xff1a;apache-flume-1.9.0-bin.tar.gz 链接: https://pan.baidu.com/s/1DXMA4PxdDtUQeMB4J62xoQ 提取码: euz7 --来自百度网盘超级会员v4的分享 ----…

centos7 安装helm v3

文章目录 1. 安装 Helm v3步骤 1&#xff1a;下载 Helm 安装包步骤 2&#xff1a;解压安装包步骤 3&#xff1a;将 Helm 移动到 /usr/local/bin步骤 4&#xff1a;验证安装 2. 使用 Helm 配置 Kubernetes步骤 1&#xff1a;安装并配置 kubectl步骤 2&#xff1a;初始化 Helm步骤…

Hive基础面试-如何理解复用率的

1. 模型的复用率你们是怎么做的&#xff1f; 简单直白的说就是你的模型复用率如何&#xff0c;在业务方是否认可该模型&#xff0c;也是衡量模型建设的一个标准&#xff0c;复用率数&#xff1a;数仓模型涉及的核心是追求模型的复用和共享&#xff0c;引用系数越高&#xff0c;…

eduSRC挖洞思路

声明 学习视频来自 B 站UP主泷羽sec&#xff0c;如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识&#xff0c;以下网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 ✍&#x1f3fb;作者简介&#xff1a;致…

Banana Pi BPI-CanMV-K230D-Zero 采用嘉楠科技 K230D RISC-V芯片设计

概述 Banana Pi BPI-CanMV-K230D-Zero 采用嘉楠科技 K230D RISC-V芯片设计,探索 RISC-V Vector1.0 的前沿技术&#xff0c;选择嘉楠科技的 Canmv K230D Zero 开发板。这款创新的开发板是由嘉楠科技与香蕉派开源社区联合设计研发&#xff0c;搭载了先进的勘智 K230D 芯片。 K230…

昆山网站建设在移动互联网时代的作用

在当今的移动互联网时代&#xff0c;昆山网站建设的重要性愈加凸显。随着智能手机和移动设备的普及&#xff0c;用户获取信息和进行消费的方式发生了根本性的变革。企业在此背景下&#xff0c;必须重新审视自己的在线形象和运营策略&#xff0c;以适应这一变化带来的挑战和机遇…

AI赋能 Python编程之2. 从构思到优化:用AI快速实现Python项目

AI赋能 Python编程 2. 从构思到优化&#xff1a;用AI快速实现Python项目 利用AI生成完整的Python项目&#xff0c;可以帮助程序员&#xff0c;尤其是初学者&#xff0c;高效完成从项目构思到实现的全过程。本文以开发一个简单的计算器应用为例&#xff0c;分享了如何借助AI的…

Spring ApplicationListener

【JavaWeb】Spring ApplicationListener-CSDN博客

MFC 下拉框显示问题和控件自适应窗口大小

在mfc开发过程中&#xff0c;遇到了下拉框的两个问题&#xff0c;现在记录一下 1、把下拉框点开显示不全我放进去的多条文本 解决办法&#xff1a;把鼠标放到下拉框的倒三角去点一下&#xff0c;鼠标就会变成双向箭头&#xff0c;或者先选中一下下拉框再把鼠标移动到倒三角上去…

【Python-办公自动化】实现自动化输出模板表格报告

import pandas as pd import numpy as np# 定义时间范围 date_range = pd.date_range(start=2023-11-01, end=2024-10-31, freq=M