JDK源码阅读之Integer_java integer中的 digitones digittens 算法-程序员宅基地

技术标签: 源码阅读  Integer  JDK  java  源码  

Integer

      我们在学习对象的自动装箱和自动拆箱时首次接触的就是Integer类。同时我们知道如果新建小数字对象其实是同一个对象,那么这之中的奥秘是什么呢?现在我们从源码的角度剖析一下吧!

类定义

public final class Integer extends Number implements Comparable<Integer>{
    
   ......
}

我们可以了解到以下信息:

  1. Integer不可以被继承;
  2. 继承Number类,所以有intValue()、longValue()、floatVaule()、doubleValue()、byteValue()和shortValue()方法;
  3. 实现了Comparable接口,可以使用compareTo方法,并且只能和Integer进行比较。

属性

private final int value;
@Native public static final int   MIN_VALUE = 0x80000000;//-2147483648
@Native public static final int   MAX_VALUE = 0x7fffffff;//2147483647
//表示基本类型 int 的 Class 实例。
public static final Class  TYPE = (Class) Class.getPrimitiveClass("int");
//用来以二进制补码形式表示 int 值的比特位数。
public static final int SIZE = 32;
//用来以二进制补码形式表示 int 值的字节数。1.8以后才有
public static final int BYTES = SIZE / Byte.SIZE;

      Integer的值存在value中,并且我们可以发现value是不可更改的。那么为什么我们初始化一个Integer对象后还可以改变它的值呢?其实本质上是新创建了一个对象,将原对象指向新对象而已。

Integer i = new Integer(1);
System.out.println(i);//1
i = 5;//底层==>i = Integer.valueOf(5);
System.out.println(i);//5

构造方法

public Integer(int value) {
    
    this.value = value;
}

      直接传入int类型的值创建Integer对象。

public Integer(String s) throws NumberFormatException {
    
     this.value = parseInt(s, 10);
}

      传入String类型,使用parseInt()函数将字符串转为十进制的数字赋值给value。转换出错则抛出NumberFormatException。

valueOf(int i)

public static Integer valueOf(int i) {
    
	if (i >= IntegerCache.low &amp;&amp; i <= IntegerCache.high)//判断i是否在缓存的数字范围内
		return IntegerCache.cache[i + (-IntegerCache.low)];//直接返回已经缓存的对象
	return new Integer(i);//不再缓存的数字范围,直接新建对象返回
}

      在默认情况向low=-128,high=127,但是high是可以通过配置进行修改的。IntegerCache代码如下:

private static class IntegerCache {
    
	static final int low = -128;
	static final int high;
	static final Integer cache[];

	static {
    
		// high value may be configured by property//说明了high的值是可以修改的
		int h = 127;
		String integerCacheHighPropValue =
			sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");//配置java.lang.Integer.IntegerCache.high即可修改high的值了
		if (integerCacheHighPropValue != null) {
    
			try {
    
				int i = parseInt(integerCacheHighPropValue);
				i = Math.max(i, 127);
				// Maximum array size is Integer.MAX_VALUE
				h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
			} catch( NumberFormatException nfe) {
    
				// If the property cannot be parsed into an int, ignore it.
			}
		}
		high = h;

		cache = new Integer[(high - low) + 1];
		int j = low;
		for(int k = 0; k < cache.length; k++)
			cache[k] = new Integer(j++);//所谓的缓存就是一个数组,里面已经创建了[-128,,127]的所有实例

		// range [-128, 127] must be interned (JLS7 5.1.7)
		assert IntegerCache.high >= 127;
	}

	private IntegerCache() {
    }
}

      当把一个int变量转成Integer的时候(或者新建一个Integer的时候),建议使用valueOf方法来代替构造函数。或者直接使用Integer i = 100;编译器会转成Integer s = Integer.valueOf(10000)。

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.println(i==j);//false
Integer m = Integer.valueOf(100);
Integer n = Integer.valueOf(100);
System.out.println(m==n);//true

String转int相关

parseInt(String s, int radix)

      将字符串s转为radix进制的数字,支持的进制范围为[2,36],超过范围抛出NumberFormatException。如果转换错误也抛出NumberFormatException。需要注意的是,parseInt返回的是int类型。

public static int parseInt(String s, int radix) throws NumberFormatException{
    
	//省略参数校验部分代码
	int result = 0;
	boolean negative = false;
	int i = 0, len = s.length();
	int limit = -Integer.MAX_VALUE;
	int multmin;
	int digit;

	if (len > 0) {
    
		char firstChar = s.charAt(0);//判断第一个字符是不是'-'或'+'
		if (firstChar < '0') {
     // Possible leading "+" or "-"
			if (firstChar == '-') {
    
				negative = true;//首字符为'-',说明是负数
				limit = Integer.MIN_VALUE;//最小值为Integer.MIN_VALUE
			} else if (firstChar != '+')
				throw NumberFormatException.forInputString(s);//首字符不是'-'或'+',直接抛出异常

			if (len == 1) // Cannot have lone "+" or "-"
				throw NumberFormatException.forInputString(s);//不能单独一个'-'或'+'
			i++;
		}
		multmin = limit / radix;
		//假设最小范围为?-2147483647?,那么在等同于-?214748364*10-digit,
		//在加最后一位前如果发现result<-?214748364,那么最后结果一定是超出范围了?
		while (i < len) {
    
			// Accumulating negatively avoids surprises near MAX_VALUE
			digit = Character.digit(s.charAt(i++),radix);//获取字符对应进制的数字
			if (digit < 0) {
    
				throw NumberFormatException.forInputString(s);
			}
			if (result < multmin) {
    
				throw NumberFormatException.forInputString(s);//超出Integer范围
			}
			result *= radix;
			if (result < limit + digit) {
    
				throw NumberFormatException.forInputString(s);//超出Integer范围
			}
			result -= digit;
		}
	} else {
    
		throw NumberFormatException.forInputString(s);
	}
	return negative ? result : -result;//负数直接返回result,正数取反
}

getInteger(String nm,Integer val)

      使用指定的名字获取系统属性值。如果没有对应名字的属性且val没有指定默认值则返回null,否则返回系统属性值或val。getInteger返回的是Integer类型。

Properties p = System.getProperties();
p.put("key1","100");
System.out.println(Integer.getInteger("key1"));//100
System.out.println(Integer.getInteger("key2"));//null
System.out.println(Integer.getInteger("key2",500));//500
p.put("key3",300);//值为int类型,不是String类型
System.out.println(Integer.getInteger("key3"));//null

int转String相关

toString(int i)

public static String toString(int i) {
    
	if (i == Integer.MIN_VALUE)//由于2147483648大于Integer.MAX_VALUE,所以需要单独处理
		return "-2147483648";
	int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);//确定申请char[]的大小
	char[] buf = new char[size];
	getChars(i, size, buf);
	return new String(buf, true);
}

final static int [] sizeTable = {
     9, 99, 999, 9999, 99999, 999999, 9999999,
								  99999999, 999999999, Integer.MAX_VALUE };

//确定需要多少位
static int stringSize(int x) {
    
	for (int i=0; ; i++)
		if (x <= sizeTable[i])
			return i+1;
}

static void getChars(int i, int index, char[] buf) {
    
	int q, r;
	int charPos = index;
	char sign = 0;

	if (i < 0) {
    
		sign = '-';//是负数,首位为'-'号
		i = -i;
	}

	// 每一次需要会产生最后两位数字
	while (i >= 65536) {
    
		q = i / 100;
		// really: r = i - (q * 100);
		r = i - ((q << 6) + (q << 5) + (q << 2));//移位的效率比直接乘除的效率要高
		i = q;
		buf [--charPos] = DigitOnes[r];//获取个位上的数字
		buf [--charPos] = DigitTens[r];//获取十位上的数字
	}

	// Fall thru to fast mode for smaller numbers
	// assert(i <= 65536, i);
	for (;;) {
    
		q = (i * 52429) >>> (16+3);//这里其实就是除以10//移位的效率比直接乘除的效率要高//乘法效率比除法高
		r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
		buf [--charPos] = digits [r];
		i = q;
		if (i == 0) break;
	}
	if (sign != 0) {
    
		buf [--charPos] = sign;
	}
}

      在第二个循环中i*52429>>>19,等同于i * 52429 / 524288,即 i * 0.1。

hashCode()

public int hashCode() {
    
	return Integer.hashCode(value);
}
public static int hashCode(int value) {
    
	return value;
}

      Integer的hash值就是value的值。

文章同步至【个人站】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_25343557/article/details/99845472

智能推荐

html+css+jQuery写的选择题答题页面_html制作答题网页-程序员宅基地

文章浏览阅读1.5k次。主要是一个选择题和多选题的答题功能使用html+css+js_html制作答题网页

SAP MRP Made Easy -[1.4]维护和定义策略及策略组_mrp主数据维护要点-程序员宅基地

文章浏览阅读8.7k次。Maintaining and Defining Strategies and Strategy Groups 维护和定义策略及策略组 The planning strategies represent the business procedures to plan and produce a material. In the system, the planning strategies a_mrp主数据维护要点

解决若依验证码异常:Error: image == null_若依验证码图片加载不出来-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。前两天在改项目突然发现若依的框架可以正常启动但是验证码加载不出来了,一直弹窗提示异常信息,下边是关于问题的描述和解决方案,没有耐心看过程的建议直接滑到最底下看解决方式解决方式: @ConfigurationProperties(prefix = “tools”) 中的 prefix 属性对应上 application.yml 文件中的属性名称就可以了@Component// 项目名称对应的 yaml 文件内容应该是# 项目相关配置tools:# 名称# 版本。_若依验证码图片加载不出来

原生js实现搜索历史记录案例_js 最近搜索记录-程序员宅基地

文章浏览阅读2.6k次,点赞8次,收藏22次。<header> <input type="text" id="search"> <input type="button" id="btn" value="搜索"> </header> <main> <div> <h3>搜索记录</h3> <span id="clear">清空&l..._js 最近搜索记录

熟悉RMAN-程序员宅基地

文章浏览阅读290次。1.1 启动,关闭数据库 C:\Users\Aiolos>RMAN TARGET / 关闭:RMAN> SHUTDOWN IMMEDIATE 启动:RMAN> STARTUP MOUNT->RMAN> ALTER DATABASE OPEN;1.2 执行操作系统命令 RMAN> HOST;--进入到操作系统的命令环境 C:\Users\Aiolos>exit --

spring解决跨域-程序员宅基地

文章浏览阅读77次。https://blog.csdn.net/qq_43486273/article/details/832725001.使用过滤器解决跨域问题package com.zhizous.blogs.servlet;import org.springframework.stereotype.Component;import javax.servlet.*;imp..._zhizous

随便推点

Coursera 申请助学金流程和材料_coursera 助学金-程序员宅基地

Coursera是一个非常受欢迎的在线学习平台,本文介绍了在Coursera申请助学金的流程和所需材料。通过选择感兴趣的课程并提交申请,等待15天后会得到申请结果。完成课程后可以获得正式的结课证书。同时,对于可以七天试用的课程,试用期内完成的证书可以免费下载。

Spring Boot 日志配置_springboot指定日志配置文件-程序员宅基地

文章浏览阅读2.5k次,点赞3次,收藏10次。引用步骤(1)编写配置文件在src/main/resources下面添加logback.xml,内容如下:<?xml version="1.0" encoding="UTF-8"?><configuration> <!--======================================= 本地变量 ======================================== --> <!--在没有定义${LOG_.._springboot指定日志配置文件

linux gcc 查看版本号,如何查看Linux或者gcc版本-程序员宅基地

文章浏览阅读1.8w次,点赞3次,收藏6次。匿名用户1级2016-12-29 回答1. 查看Linux版本cat/etc/issueLinaro 12.07 \n \l2. 查看内核版本1)cat/proc/versionLinux version 2.6.38-13-generic(buildd@rothera) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)) #57-Ubuntu S..._gcc version

802.1x之CA证书的配置-程序员宅基地

文章浏览阅读1.2k次。之前一直有人问CA证书怎么配置才能成功使用.现将我参考的一篇文章贡献出来,希望对大家有所帮助。注:这里引用的文章是实现智能卡与证书所需要的配置,如果想使用PEAP,原理类似,证书不太一样就是了。下面的表格有写出来。大家举一反三,自己做吧。使用EAP-TLS(智能卡与证书)实现802.1X----验证服务器和交换机相关配置For this configuration..._802.1x 证书

操作系统课设——页面置换算法的模拟_页面置换算法模拟程序-程序员宅基地

文章浏览阅读2.3k次。本课设主要实现FIFO算法和LRU算法,虽然实现了功能,但是个人感觉代码可以优化,而且采用的主存块数是3,如果主存块数修改了,那么代码也需要修改,这是我课设不足之处,望大神来指教!下面是我的代码#include #include #define PAGE_NUM 3 //主存块数#define SERIAL_NUM 12 //访问序列的次数int serial[SERI_页面置换算法模拟程序

Android开发经验谈:请谈下Android消息机制,已拿到offer-程序员宅基地

文章浏览阅读139次。开头很多人说Android开发前景越来越差了 我觉得这个回答是片面的首先Android应用开发前景差是在最近两年出现的,也就是从2018开始,从那时起移动端的程序员已经慢慢出现供大于求的局面,本人作为移动端开发,深知这一点。然而也必须说明一点,不论是Android开发还是iOS开发,虽然都出现了相关的程序员供大于求的情况,但市场仍然是有需求的,特别是对资深的开发人员及拥有相关底层开发知识的应用程序员市场及发展还是很多的;这里所讲的就业难都是相对于初级开发人员。为什么会在18年出现应用端就业难?这是由