Java源码分析(一)Integer
当你掌握Java语言到了一定的阶段,或者说已经对Java的常用类和API都使用的行云流水。你会不会有一些思考?比如,这个类是如何设计的?这个方法是怎么实现的?接下来的一系列文章,我们一起学习下Java的一些常见类的源码。本篇,一起分析下Integer的源码。
目录
一、两道Integer的题目
二、Integer类图
三、String转int
1、Integer.parseInt
2、Integer.valueOf
四、总结
一、两道Integer的题目
可能有些同学java水平比较高,或者认为自己没必要去看Integer源码。那你不妨看下接下来这几道题目,看看你是否都能答对。
1、如下代码输出什么?
public class IntegerTest1 {public static void main(String[] args) {Integer i1 = 100;Integer i2 = 100;Integer i3 = 200;Integer i4 = 200;System.out.println(i1 == i2);System.out.println(i3 == i4);}
}
答案是:true false
2、如下代码输出什么?
public class IntegerTest {public static void main(String[] args) {String s = "10";System.out.println(Integer.getInteger(s));}
}
答案是:null(咦,为什么不是10?)
如果这两道题目都答对了,那你可以叉掉这篇文章,因为我也不想浪费你的时间。如果你答错了,那么不妨一起学习下Integer的源码?
二、Integer类图
那么,接下来,我们一起看下Integer的源码吧。Integer源码不算短,1800+行代码。其中有很多api是不常用的,因此,我们也仅去挑一些常用的api去看下其实现。如下是Integer及其关联类/接口的类图:

通过Integer类的类图,我们总结下它的特点:
- Integer类继承自抽象类Number
- Integer类实现了Comparable接口
- Integer类使用final修饰,因此不可以有子类(不能被继承)
三、String转int
在日常工作中,我们经常会将一个代表数字的String,转为int,那么Java给我们提供了两个方法:
1、Integer.parseInt
public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);}
在使用这个方法的时候,我们需要注意trycatch一下NumberFormatException,否则当输入的String不是数字或者超过integer的范围时会产生异常。
另外,该方法默认是10进制,当然我们也可以调用两个参数的方法传入进制去转为其他进制的int,但这不常用:
public static int parseInt(String s, int radix)throws NumberFormatException{...}
接下来,详细看下该方法的实现:
首先,会判断传入的String不为null,检验传入的进制参数在范围内[2 , 36],而且会判断字符串的长度大于0,否则会抛出NumberFormatException:
if (s == null) {throw new NumberFormatException("null");}if (radix < Character.MIN_RADIX) {throw new NumberFormatException("radix " + radix +" less than Character.MIN_RADIX");}if (radix > Character.MAX_RADIX) {throw new NumberFormatException("radix " + radix +" greater than Character.MAX_RADIX");}if (len > 0) {...} else {throw NumberFormatException.forInputString(s);}
当字符串满足转化为int的条件时,就执行将String转为int的代码(上述被...省略的代码)。我们也分两步来看:
首先,根据字符串的首字符判断是正数、负数或是非法。
char firstChar = s.charAt(0);if (firstChar < '0') { // Possible leading "+" or "-"if (firstChar == '-') {negative = true;limit = Integer.MIN_VALUE;} else if (firstChar != '+') {throw NumberFormatException.forInputString(s);}if (len == 1) { // Cannot have lone "+" or "-"throw NumberFormatException.forInputString(s);}i++;}
(1)如果第一个字符是'-',会把表示正负数的negative置为true,同时把其limit置为Integer的最小值;
(2)如果不是'-'且如果不是'+',那说明是其他的字符,抛出异常;
(3)如果首字符是'+'或'-',但是长度为1,说明是"+"或"-",也是非数字,抛出异常。
(4)如果首字符合法,那么i++,接下来看非符号的字符。
当然,如果首字符不是符号,而是数字,那么就直接走接下来的代码:
int multmin = limit / radix;int result = 0;while (i < len) {// Accumulating negatively avoids surprises near MAX_VALUEint digit = Character.digit(s.charAt(i++), radix);if (digit < 0 || result < multmin) {throw NumberFormatException.forInputString(s);}result *= radix;if (result < limit + digit) {throw NumberFormatException.forInputString(s);}result -= digit;}return negative ? result : -result;
(1)遍历字符串的字符,调用digit函数,该函数在不能转为数字时返回-1
(2)如果有字符不是数字(digit<0),那么抛出异常。
(3)如果没问题,那就一步步计算转为int,会判断是否超过范围,超过范围则抛出异常
(4)最后,如果是负数返回result,如果是正数,返回-result
在这里,可能有的同学没看懂,为什么负数返回的是result,而正数返回的是-result。我们把字符串数字转为十进制的方法,比如把"1234"转为十进制,其实是这么来的:
((((1 ✖️10)+ 2)✖️10) + 3)✖️10 + 4
= ((12 ✖️10) + 3) ✖️10 + 4
= (120 + 3)✖️10 + 4
= 123✖️10 + 4
= 1230 + 4
= 1234
而方法里面其实是反过来实现的:
((((-1 ✖️10)- 2)✖️10) - 3)✖️10 - 4
= ((-12 ✖️10) - 3) ✖️10 - 4
= (-120 - 3)✖️10 - 4
= -123✖️10 - 4
= -1230 - 4
= -1234
所以,它用的不是正向累加法,而是负向累加法。其实代码里面也有注释(负向累加避免在最大值附近发生意外):
// Accumulating negatively avoids surprises near MAX_VALUE
2、Integer.valueOf
第二种方法就是Integer.valueOf,该方法最后还是调用的parseInt。注意其返回值是Integer,而不是int。不过,现在已经不用unboxing了,可以直接使用int去接收返回值。
public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));}
接下来,看看valueOf的实现:
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
suprise来了,Integer.valueOf( int i)这个方法,出现了IntegerCache这个内部类,而且会返回cache里的对象或者一个新的Integer对象。那么,IntegerCache是什么?
private static class IntegerCache {static final int low = -128;static final int high;static final Integer[] cache;static Integer[] archivedCache;private IntegerCache() {}static {int h = 127;String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");int size;if (integerCacheHighPropValue != null) {try {size = Integer.parseInt(integerCacheHighPropValue);size = Math.max(size, 127);h = Math.min(size, 2147483518);} catch (NumberFormatException var6) {}}high = h;VM.initializeFromArchive(Integer.IntegerCache.class);size = high - -128 + 1;if (archivedCache == null || size > archivedCache.length) {Integer[] c = new Integer[size];int j = -128;for(int k = 0; k < c.length; ++k) {c[k] = new Integer(j++);}archivedCache = c;}cache = archivedCache;assert high >= 127;}}
可以看出,Integer内部维护了一个IntegerCache,范围是[-128,127]。valueOf方法,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
这其实解答了我们的第一个问题。 在这里顺便也看下我们的第二个问题,为什么Integer.getInteger("10")返回的是null,而不是10。其实调用的是System.getProperty,跟String转int半毛钱关系没有:
public static Integer getInteger(String nm, Integer val) {String v = null;try {v = System.getProperty(nm);} catch (IllegalArgumentException | NullPointerException e) {}if (v != null) {try {return Integer.decode(v);} catch (NumberFormatException e) {}}return val;}
四、总结
其实Integer我们常用的无非就是这两个String转int的方法,Integer还提供了一些简单的计算方法例如max,min,sum,其实我们也用不到。还有intValue方法,从java1.6开始,我们也不需要拆箱(unboxing)了,所以也用不到。
本篇基于Integer的两个常用方法,看了其关键代码的实现,也知道了其内部维护着一个缓存。通过分析其源码实现,也解答了开篇抛出的两个问题。
相关文章:
Java源码分析(一)Integer
当你掌握Java语言到了一定的阶段,或者说已经对Java的常用类和API都使用的行云流水。你会不会有一些思考?比如,这个类是如何设计的?这个方法是怎么实现的?接下来的一系列文章,我们一起学习下Java的一些常见类…...
WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机
WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机 在之前已经实现了WebRTC调用ossrs服务,实现直播视频通话功能。但是在使用过程中,RTCCameraVideoCapturer类提供的方法不能修改及调节相机的灯光等设置,那就需要自定义RTCVideoCaptur…...
【基于鲲鹏及openEuler20.03TLS下MySQL8.0.17性能调优】
【基于鲲鹏及openEuler20.03TLS下MySQL8.0.17性能调优】 一、环境说明二、实验过程三、实验小结 一、环境说明 华为云ECS 规格:8vCPU 32G arm架构操作系统:openEuler 20.03.TLSMySQL版本:8.0.17 二、实验过程 创建用户及用户组:…...
GRPC 学习记录
GRPC 安装 安装 grpcio、grpcio-tools、protobuf、 pip install grpcio -i https://pypi.tuna.tsinghua.edu.cn/simple pip install grpcio-tools -i https://pypi.tuna.tsinghua.edu.cn/simple pip install protobuf -i https://pypi.tuna.tsinghua.edu.cn/simple常用类型 p…...
C++语言的QT写软件界面,结合python深度学习模型的综合应用处理方案
C与python问题合集: 后面内容涉及到api的创建问题 如果我用C语言的QT写软件界面,然后用python语言去写和人工智能相关的东西。就比如说一些模型,那么现在我想将用python写的模型放在QT写的软件当中调用,那么请问是否会导致C语言…...
Linux环境下python连接Oracle教程
下载Oracle client需要的 安装包 rpm包下载地址:Oracle官方下载地址 选择系统版本 选择Oracle版本 下载3个rpm安装包 oracle-instantclient12.2-basic-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-devel-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-sq…...
第 7 章 排序算法(1)
7.1排序算法的介绍 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。 7.2排序的分类: 内部排序: 指将需要处理的所有数据都加载到**内部存储器(内存)**中进行排序。外部排序法: 数据量过大&am…...
wsl,字体乱码问题
配置wsl,字体乱码问题 一、前言 用zsh配置好wsl,每次打开还是会出现乱码,只有再新打开一个终端才会显示字体 如下图:第一次打开,出现乱码 如图:按加号,再开一个新终端才会显示字体。 二、解…...
【NetCore】10-路由定义
文章目录 路由与终结点:如何规划好Web Api1. 路由1.1 路由映射1.2 路由注册方式1.3 路由约束总结: Web Api定义 路由与终结点:如何规划好Web Api 1. 路由 1.1 路由映射 路由系统核心作用是指URL和应用程序Controller的对应关系的一种映射 这种映射的作…...
软考:中级软件设计师:数据库模式、ER模型
软考:中级软件设计师:数据库模式、ER模型 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准…...
海量数据迁移,亚马逊云科技云数据库服务为大库治理提供新思路
1.背景 目前,文档型数据库由于灵活的schema和接近关系型数据库的访问特点,被广泛应用,尤其是游戏、互联网金融等行业的客户使用MongoDB构建了大量应用程序,比如游戏客户用来处理玩家的属性信息;又如股票APP用来存储与时…...
DevOps系列文章之 GitlabCICD自动化部署SpringBoot项目
一、概述 本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。 二、前期准备 准备三台 CentOS7服务器,分别部署以下服务: 序号系统IP服务1CentOS7192.168.56.10Gitlab2CentOS7192.168.56.11Runner (安装Docker)3Cen…...
汽车租赁管理系统/汽车租赁网站的设计与实现
摘 要 租赁汽车走进社区,走进生活,成为当今生活中不可缺少的一部分。随着汽车租赁业的发展,加强管理和规范管理司促进汽车租赁业健康发展的重要推动力。汽车租赁业为道路运输车辆一种新的融资服务形式、广大人民群众一种新的出行消费方式和…...
语句覆盖、条件覆盖、判定覆盖、条件-判定覆盖、路径覆盖
白盒测试是结构测试,主要对代码的逻辑进行验证。 逻辑覆盖率:语句覆盖<条件覆盖<判定覆盖<条件-判定覆盖<组合覆盖<路径覆盖 例子 一、语句覆盖 最基础的覆盖,只要每一个执行处理框内的语句都能执行就可,不用关注…...
二进制逻辑运算符
运算的优先级:非>与>或 1.逻辑与:“ ∧ \wedge ∧“,“ ⋅ \cdot ⋅“,and 在逻辑问题中与是所有的都是真结果才是真,比如: 1010101011 1010101011 1010101011和 1010110010 1010110010 1010110010…...
Bug日记-webstorm运行yarn 命令报错
在windows中输入yarn -v正确输出,在webstrom终端中运行yarn命令输出错误 问题:可能是由于 WebStorm 配置问题导致的。 解决方案: 检查 WebStorm 的终端配置:在 WebStorm 中,点击菜单栏的 “File”(文件&am…...
C++11并发与多线程笔记(9) async、future、packaged_task、promise
C11并发与多线程笔记(9) async、future、packaged_task、promise 1、std::async、std::future创建后台任务并返回值2、std::packaged_task:打包任务,把任务包装起来3、std::promise3、小结 1、std::async、std::future创建后台任务…...
Mr. Cappuccino的第63杯咖啡——Spring之AnnotationConfigApplicationContext源码分析
Spring之AnnotationConfigApplicationContext源码分析 源码分析 源码分析 以上一篇文章《Spring之Bean的生命周期》的代码进行源码分析 AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(SpringConfig02.class); LifeCycleBe…...
opencv直方图与模板匹配
import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows() 直方图 cv2.calcHist(images,channels,mask,histSize,ran…...
Apache Doris 入门教程31:计算节点
需求场景 目前Doris是一个典型Share-Nothing的架构, 通过绑定数据和计算资源在同一个节点获得非常好的性能表现. 但随着Doris计算引擎性能持续提高, 越来越多的用户也开始选择使用Doris直接查询数据湖数据. 这类场景是一种Share-Disk场景, 数据往往存储在远端的HDFS/S3上, 计…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
