有关Java中您所不明了的Integer详解

作者:操作系统

有关Java中你所不亮堂的Integer详解,javainteger详解

前言

本文首要给我们介绍了有关Java中Integer的连带内容,分享出来供大家参照他事他说加以考察学习,上面话十分少说了,来一块看看详细的介绍吧。

实参形参

前几天见到生活圈分享了一片小说《Java函数的传参机制——你实在领悟呢?》

稍加触发,在此以前也商讨过Java的Integer,所以写下本文,希望对您全体利于。

交换

先是来看三个示范。

请用Java达成swap函数,调换多个整数类型的值。

public static void test() throws Exception {
 Integer a = 1, b = 2;
 swap(a, b);
 System.out.println("a=" + a + ", b=" + b);
}

static void swap(Integer a, Integer b){
 // 需要实现的部分
}

第一次

万一您不停解Java对象在内部存款和储蓄器中的分配办公室法,以及艺术传递参数的方式,你有望会写出以下代码。

public static void swapOne(Integer a, Integer b) throws Exception {
 Integer aTempValue = a;
 a = b;
 b = aTempValue;
}

运维的结果展现a和b八个值并不曾交流。

那么让我们来看一下上述程序运维时,Java对象在内部存款和储蓄器中的分配格局:

金冠53777 1
指标地址分配

通过能够观望,在八个章程的有个别变量表中分别有着的是对a、b八个对象实际数目地址的援引。

上边实现的swap函数,仅仅沟通了swap函数里一些变量a和有些变量b的援引,并从未交换JVM堆中的实际数目。

为此main函数中的a、b引用的多寡未有产生交换,所以main函数中有些变量的a、b并不会产生变化。

那么要换到main函数中的数据要什么操作呢?

第二次

依据上边的实施,可以虚构交流a和b在JVM堆上的数据值?

简来说之询问一下Integer那些指标,它里面唯有三个指标级int类型的value用以表示该对象的值。

故而大家接纳反射来修改该值,代码如下:

public static void swapTwo(Integer a1, Integer b1) throws Exception {
 Field valueField = Integer.class.getDeclaredField("value");
 valueField.setAccessible(true);
 int tempAValue = valueField.getInt(a1);
 valueField.setInt(a1, b1.intValue());
 valueField.setInt(b1, tempAValue);
}

运作结果,相符预期。

惊喜

地点的程序运营成后,借使自身在宣称贰个Integer c = 1, d = 2;会有如何结果

示范程序如下:

public static void swapTwo(Integer a1, Integer b1) throws Exception {
 Field valueField = Integer.class.getDeclaredField("value");
 valueField.setAccessible(true);
 int tempAValue = valueField.getInt(a1);
 valueField.setInt(a1, b1.intValue());
 valueField.setInt(b1, tempAValue);
}

public static void testThree() throws Exception {
 Integer a = 1, b = 2;
 swapTwo(a, b);
 System.out.println("a=" + a + "; b=" + b);
 Integer c = 1, d = 2;
 System.out.println("c=" + c + "; d=" + d);
}

输出的结果如下:

a=2; b=1
c=2; d=1

惊奇不欣喜!意外平常!激情不激情!

深入

到底发生了怎样?让大家来看一下反编写翻译后的代码:

小编接纳IDE工具,直接反编写翻译了这些.class文件

public static void testThree() throws Exception {
 Integer a = Integer.valueOf(1);
 Integer b = Integer.valueOf(2);
 swapTwo(a, b);
 System.out.println("a=" + a + "; b=" + b);
 Integer c = Integer.valueOf(1);
 Integer d = Integer.valueOf(2);
 System.out.println("c=" + c + "; d=" + d);
}

在Java对原始类型int自动装箱到Integer类型的经过中行使了Integer.valueOf(int)本条方式了。

确定是以此办法在其间封装了一部分操作,使得大家修改了Integer.value后,产生了全局影响。

抱有那件事关该部分的代码三次性粘完(PS:不拖拉的小编是个好码农):

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

 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
 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;
 }

 private IntegerCache() {}
 }

}

如上所示Integer内部有二个民用静态类IntegerCache,该类静态起始化了一个含有了Integer.IntegerCache.lowjava.lang.Integer.IntegerCache.high的Integer数组。

其中java.lang.Integer.IntegerCache.high的取值范围在[127~Integer.MAX_VALUE - (-low) -1]之间。

在该距离内享有的Integer.valueOf(int)函数重回的靶子,是依据int值总结的偏移量,从数组Integer.IntegerCache.cache中获得,对象是同贰个,不会新建对象。

故此当大家修改了Integer.valueOf(1)的value后,所有Integer.IntegerCache.cache[ 1 - IntegerCache.low ]的重回值都会变动。

自己深信不疑你们的智力应该明白了,倘使不知底请在批评区call 10086。

好了,那么不在[IntegerCache.low~IntegerCache.high)的片段吗?

很明显,它们是还好的,未有被IntegerCache缓存到,法外之民,每趟它们的赶来,都会new一边,在JVM上分红一块土(内)地(存)。

遐想

即便本身把转变的参数换到类型换到int呢?

public static void testOne() throws Exception {
 int a = 1, b = 2;
 swapOne(a, b);
 System.out.println("a=" + a + ", b=" + b);
}

static void swapOne(int a, int b){
 // 需要实现的部分
}

以笔者方今的功力,无解。高手能够民众号留言,十分感激!

由来swap部分已经说罢了。

1 + 1

先是让大家来看一下代码:

public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
}

请问输出是怎么样?

假定你势必的说是2,那么您上面是白学了,请直接拨打95169。

自家能够一定的告知您,它能够是[Integer.MIN_VALUE~Integer.MAX_VALUE]间隔的任性一个值。

欣喜不惊奇!意外不意外!激情不激情!

让我们再撸(捋)一(一)串(遍)烧(代)烤(码)。

小编运用IDE工具,直接反编写翻译了这些.class文件

public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
}

此处的变量two竟然未有调用Integer.valueOf(int),跟想象的不太同样,笔者难以置信那是IDE的锅。

之所以果决查看编写翻译后的字节码。以下为摘录的一些字节码:

LDC "Two=%d"
ICONST_1
ANEWARRAY java/lang/Object
DUP
ICONST_0
ILOAD 2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
AASTORE
INVOKEVIRTUAL java/io/PrintStream.printf (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
POP

金冠53777,能够看看确实是IDE的锅,这里不仅仅调用了壹回Integer.valueOf(int),而且还创建一个Object的数组。

完整的Java代码应该是之类所示:

public static void testOne() {
 int one = 1;
 int two = one + one;
 Object[] params = { Integer.valueOf(two) };
 System.out.printf("Two=%d", params);
}

之所以一旦在艺术调用前修改Integer.IntegerCache.cache[2+128]的值就能够了,所以在类的静态开头化部分加些代码。

public class OnePlusOne {
 static {
 try {
 Class<?> cacheClazz = Class.forName("java.lang.Integer$IntegerCache");
 Field cacheField = cacheClazz.getDeclaredField("cache");
 cacheField.setAccessible(true);
 Integer[] cache = (Integer[]) cacheField.get(null);
 //这里修改为 1 + 1 = 3 
 cache[2 + 128] = new Integer(3);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

 public static void testOne() {
 int one = 1;
 int two = one + one;
 System.out.printf("Two=%d", two);
 }
}

two == 2 ?

在改换完Integer.IntegerCache.cache[2 + 128]的值后,变量two还等于2么?

public static void testTwo() {
 int one = 1;
 int two = one + one;
 System.out.println(two == 2);
 System.out.println(Integer.valueOf(two) == 2);
}

上述代码输出如下

true
false

因为two == 2不涉及到Integer装箱的改换,仍然原始类型的可比,所以原始类型的2世代等于2。

Integer.valueOf(two)==2的诚实格局是Integer.valueOf(two).intValue == 2,即3==2,所以是false。

此处能够看出倘诺拿一个值为null的Integer变量和一个int变量用双等号比较,会抛出NullPointException。

此间的措施要是换来System.out.println("Two=" + two)的格局会有如何的出口?你可以尝试一下。

后记

XCache

是否有Cache 最小值 最大值
Boolean -- --
Byte ByteCache -128 127(固定)
Short ShortCache -128 127(固定)
Character CharacterCache 0 127(固定)
Integer IntegerCache -128 java.lang.Integer.IntegerCache.high
Long LongCache -128 127(固定)
Float -- --
Double -- --

java.lang.Integer.IntegerCache.high

看了IntegerCache类获取high的方法sun.misc.VM.getSavedProperty,或许我们会有以下难点,大家不拖拉,选用多个主题素材一解答的主意。

  1. 其一值什么如何传递到JVM中?

和系统脾气一样在JVM运转时,通过安装-Djava.lang.Integer.IntegerCache.high=xxx传递踏入。

  1. 这么些方法和System.getProperty有哪些分歧?

为了将JVM系统所急需的参数和顾客接纳的参数分裂开,
java.lang.System.initializeSystemClass在运转时,会将开发银行参数保存在八个地方:

2.1 sun.misc.VM.savedProps中保留全体JVM接收的系统参数。

JVM会在运行时,调用java.lang.System.initializeSystemClass主意,发轫化该属性。

同有的时候间也会调用sun.misc.VM.saveAndRemoveProperties方法,从java.lang.System.props中剔除以下属性:

  • sun.nio.MaxDirectMemorySize
  • sun.nio.PageAlignDirectMemory
  • sun.lang.ClassLoader.allowArraySyntax
  • java.lang.Integer.IntegerCache.high
  • sun.zip.disableMemoryMapping
  • sun.java.launcher.diag

以上罗列的质量都以JVM运营需求安装的系统参数,所认为了安全思索和隔开分离角度考虑,将其从客商可访谈的System.props分开。

2.2 java.lang.System.props中保留除了以下JVM运行要求的参数外的其余参数。

  • sun.nio.MaxDirectMemorySize
  • sun.nio.PageAlignDirectMemory
  • sun.lang.ClassLoader.allowArraySyntax
  • java.lang.Integer.IntegerCache.high
  • sun.zip.disableMemoryMapping
  • sun.java.launcher.diag

PS:笔者运用的JDK 1.8.0_91

Java 9的IntegerCache

幻想一下,假若以上顽皮的玩的方法出现在第三方的借助包中,相对有一堆技士会疯掉(请不要品味那样恶劣的玩的方法,后果异常的惨恻)。

庆幸的是Java 9对此开展了限定。能够在对应的module中编辑module-info.java文件,限制了使用反射来访谈成员等,根据须要申明后,代码只好访问字段、方法和任何用反射能访谈的音讯,只有当类在一如既往的模块中,或许模块张开了包用于反射形式访谈。详细内容可参照一下篇章:

在 Java 9 里对 IntegerCache 进行改变?

感激Lydia和飞鸟的高贵提议和劳顿查对。

末尾跟大家享用四个java中Integer值相比较不理会的难点:

先来看一个代码片段:

public static void main(String[] args) { 
Integer a1 = Integer.valueOf(60); //danielinbiti 
Integer b1 = 60; 
System.out.println("1:="+(a1 == b1)); 


Integer a2 = 60; 
Integer b2 = 60; 
System.out.println("2:="+(a2 == b2)); 


Integer a3 = new Integer(60); 
Integer b3 = 60; 
System.out.println("3:="+(a3 == b3)); 

Integer a4 = 129; 
Integer b4 = 129; 
System.out.println("4:="+(a4 == b4)); 
} 

这段代码的相比较结实,若无推行不理解诸位心中的答案都以何等。

要明了那么些答案,就涉嫌到Java缓冲区和堆的主题材料。

java中Integer类型对于-128-127里头的数是缓冲区取的,所以用等号相比较是完全一样的。但对此不在那间隔的数字是在堆中new出来的。所以地点空间不均等,也就不等于。

Integer b3=60 ,那是多少个装箱进度也便是Integer b3=Integer.valueOf(60)

所以,今后遇到Integer相比值是还是不是等于需要用intValue()

对此Double未有缓冲区。

答案

1:=true

2:=true

3:=false

4:=false

总结

上述正是那篇小说的全部内容了,希望本文的内容对我们的求学大概办事富有一定的参谋学习价值,借使有疑问大家能够留言沟通,感谢大家对帮客之家的帮忙。

前言 本文首要给我们介绍了关于Java中Integer的相干内容,分享出去供大家仿照效法学习,上面...

本文由金冠53777-金冠娱乐53777-Welcome发布,转载请注明来源

关键词: