Integer源码分析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
以上是关于Integer源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段