Integer源码分析

类定义


public final class Integer extends Number implements Comparable<Integer>

从类定义中我们可以知道以下几点:

  • Integer类不能被继承
  • Integer类实现了Comparable接口,所以可以用compareTo进行比较并且Integer对象只能和Integer类型的对象进行比较,不能和其他类型比较
  • Integer继承了Number类,所以该类可以调用longValue、floatValue、doubleValue等系列方法返回对应的类型的值。

属性


一、私有属性

Integer类中定义了以下几个私有属性:

private final int value;
private static final long serialVersionUID = 1360826667806852920L;
  • serialVersionUID和序列化有关
  • value属性就是Integer对象中真正保存int值的。

当我们使用new Integer(10)创建一个Integer对象的时候,就会用以下形式给value赋值。

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

这里我们讨论一下Interger对象的可变性。从value的定义形式中可以看出value被定义成final类型。也就说明,一旦一个Integer对象被初始化之后,就无法再改变value的值。那么这里就深入讨论一下以下代码的逻辑:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i = new Integer(10);
        i = 5;
    }
}

在以上代码中,首先调用构造函数new一个Integer对象,给私有属性value赋值,这时value=10,接下来使用i=5的形式试图改变i的值。有一点开发经验的同学都知道,这个时候如果使用变量i,那么它的值一定是5,那么i=5这个赋值操作到底做了什么呢?到底是如何改变i的值的呢?是改变了原有对象i中value的值还是重新创建了一个新的Integer对象呢?

我们将上面的代码进行反编译,反编译之后的代码如下:

public class IntegerTest
{

    public IntegerTest()
    {
    }

    public static void main(String args[])
    {
        Integer i = new Integer(10);
        i = Integer.valueOf(5);
    }
}

通过看反编译之后的代码我们发现,编译器会把i=5转成i = Integer.valueOf(5);这里先直接给出结论,i=5操作并没有改变使用Integer i = new Integer(10);创建出来的i中的value属性的值。要么是直接返回一个已有对象,要么新建一个对象。这里的具体实现细节在后面讲解valueOf方法的时候给出。

二、公共属性

//值为 (-(2的31次方)) 的常量,它表示 int 类型能够表示的最小值。
public static final int   MIN_VALUE = 0x80000000;
//值为 ((2的31次方)-1) 的常量,它表示 int 类型能够表示的最大值。
public static final int   MAX_VALUE = 0x7fffffff;
//表示基本类型 int 的 Class 实例。
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//用来以二进制补码形式表示 int 值的比特位数。
public static final int SIZE = 32;
//用来以二进制补码形式表示 int 值的字节数。1.8以后才有
public static final int BYTES = SIZE / Byte.SIZE;

以上属性可直接使用,因为他们已经定义成publis static fianl能用的时候尽量使用他们,这样不仅能使代码有很好的可读性,也能提高性能节省资源。

方法


构造方法

Integer提供了两个构造方法:

//构造一个新分配的 Integer 对象,它表示指定的 int 值。
public Integer(int value) {
    this.value = value;
}

//构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。
public Integer(String s) throws NumberFormatException {
    this.value = parseInt(s, 10);
}

从构造方法中我们可以知道,初始化一个Integer对象的时候只能创建一个十进制的整数。

Integer valueOf(int i)方法

前面说到Integer中私有属性value的时候提到

Integer i = new Integer(10);
i = 5;

其中i=5操作时,编译器会转成i = Integer.valueOf(5);执行。那么这里就解释一下valueOf(int i)方法是如何给变量赋值的。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

以上是valueOf方法的实现细节。通常情况下,IntegerCache.low=-128,IntegerCache.high=127(除非显示声明java.lang.Integer.IntegerCache.high的值),Integer中有一段动态代码块,该部分内容会在Integer类被加载的时候就执行。

static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.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++);

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

也就是说,当Integer被加载时,就新建了-128到127的所有数字并存放在Integer数组cache中。

再回到valueOf代码,可以得出结论。当调用valueOf方法(包括后面会提到的重载的参数类型包含String的valueOf方法)时,如果参数的值在-127到128之间,则直接从缓存中返回一个已经存在的对象。如果参数的值不在这个范围内,则new一个Integer对象返回。

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

String转成Integer(int)的方法

Integer getInteger(String nm)
Integer getInteger(String nm, int val)
Integer getInteger(String nm, Integer val)
Integer decode(String nm)
Integer valueOf(String s)
Integer valueOf(String s, int radix)
int parseUnsignedInt(String s)
int parseUnsignedInt(String s, int radix)
int parseInt(String s)
int parseInt(String s, int radix)

以上所有方法都能实现将String类型的值转成Integer(int)类型(如果 String 不包含可解析整数将抛出NumberFormatException)

可以说,所有将String转成Integer的方法都是基于parseInt方法实现的。简单看一下以上部分方法的调用栈。

getInteger(String nm) ---> getInteger(nm, null);--->Integer.decode()--->Integer.valueOf()--->parseInt()

getInteger

确定具有指定名称的系统属性的整数值。 第一个参数被视为系统属性的名称。通过 System.getProperty(java.lang.String) 方法可以访问系统属性。然后,将该属性的字符串值解释为一个整数值,并返回表示该值的 Integer 对象。使用 getProperty 的定义可以找到可能出现的数字格式的详细信息。其中参数nm应该在System的props中可以找到。这个方法在日常编码中很好是用到。在代码中可以用以下形式使用该方法:

Properties props = System.getProperties();
props.put("test.key","10000");
Integer i = Integer.getInteger("test.key");
System.out.println(i);
//输出 10000

总结


  • 将int转换Integet时 使用valueOf(int i)方法代替new Integer() 或者使用Integer i = 100

来自:http://www.hollischuang.com/archives/1058

时间: 2024-10-16 06:21:48

Integer源码分析的相关文章

基本类型Integer源码分析

1. 源码相关的说明参考java 8 doc https://docs.oracle.com/javase/8/docs/api/ 2.自动装箱使用缓存原理: 调用static valueOf从而使用内部静态类static class IntegerCache{},其中cache最大值可以调整,通过VM options参数调整: 说明:只有Integer能调整cache上限,其他的基本类型缓存原理都是固定值127,具体参考源码. 原文地址:https://www.cnblogs.com/jayi

JDK源码分析-Integer

Integer是平时开发中最常用的类之一,但是如果没有研究过源码很多特性和坑可能就不知道,下面深入源码来分析一下Integer的设计和实现. Integer: 继承结构: -java.lang.Object --java.lang.Number ---java.lang.Integer 其中父类Number是个抽象类,是所有数字类型相关的类的父类,例如Double.Float.Integer.Long 和 Short. Integer类还实现了Comparable接口用以比较两个Integer的

Integer面试连环炮以及源码分析

场景: ??昨天有位朋友去面试,我问他面试问了哪些问题,其中问了Integer相关的问题,以下就是面试官问的问题,还有一些是我对此做了扩展. 问:两个new Integer 128相等吗? 答:不.因为Integer缓存池默认是-127-128: 问:可以修改Integer缓存池范围吗?如何修改? 答:可以.使用-Djava.lang.Integer.IntegerCache.high=300设置Integer缓存池大小 问:Integer缓存机制使用了哪种设计模式? 答:亨元模式: 问:Int

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

redis源码分析3---结构体---字典

redis源码分析3---结构体---字典 字典,简单来说就是一种用于保存键值对的抽象数据结构: 注意,字典中每个键都是独一无二的:在redis中,内部的redis的数据库就是使用字典作为底层实现的: 1 字典的实现 在redis中,字典是使用哈希表作为底层实现的,一个hash表里面可以有多个hash表节点,而每个hash表节点就保存了字典中的一个键值对: hash表定义 table属性是一个数组,数组中的每个元素都是一个指向dictEntry结构的指针,每个dictEntry结构保存着一个键值

Mybatis源码分析之Cache二级缓存原理 (五)

一:Cache类的介绍 讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(ServiceProvider Interface) ,所有的MyBatis内部的Cache缓存,都应该实现这一接口 Cache的实现类中,Cache有不同的功能,每个功能独立,互不影响,则对于不同的Cache功能,这里使用了装饰者模式实现. 看下cache的实现类,如下图: 1.FIFOCache:先进

【JUC】JDK1.8源码分析之ConcurrentHashMap(一)

一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析,下面进行源码分析. 二.ConcurrentHashMap数据结构 之前已经提及过,ConcurrentHashMap相比HashMap而言,是多线程安全的,其底层数据与HashMap的数据结构相同,数据结构如下 说明:ConcurrentHashMap的数据结构(数组+链表+红黑树),桶中的结构

[Java] HashMap源码分析

1.概述 Hashmap继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口.它的key.value都可以为null,映射不是有序的. Hashmap不是同步的,如果想要线程安全的HashMap,可以通过Collections类的静态方法synchronizedMap获得线程安全的HashMap. Map map = Collections.synchronizedMap(new HashMap()); (除了不同步和允许使用 null 之

【JAVA集合】HashMap源码分析(转载)

原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储的对象是一个键值对对象(Entry<K,V>): HashMap补充说明 基于数组和链表实现,内部维护着一个数组table,该数组保存着每个链表的表头结点:查找时,先通过hash函数计算hash值,再根据hash值计算数组索引,然后根据索引找到链表表头结点,然后遍历查找该链表: HashMap数据