举例:

public class Test {

    @org.junit.Test
public void intTest() {
Integer t1 = 128;
Integer t2 = 127;
} }

使用 javap -c 查看字节码

public void intTest();
Code:
0: sipush 128
3: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
6: astore_1
7: bipush 127
9: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
12: astore_2
13: return

说明:

造成两种区别对待的等价方式,在于 valueOf 方法的实现:(low 与 high 分别是 -128 与 127),底层原理:IntegerCache 本质是编译期常量 static final Integer cache[], 一个 Integer 数组。

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

测试:

Integer t1 = new Integer(128);

Integer t2 = 128;

Integer t3 = 128;

int t4 = 128;

Integer t5 = 127;

Integer t6 = 127;

Integer t7 = new Integer(127);

结果:

System.out.println(t1 == t2); // false  因为 t2/t3 等价于 new Integer(128),所以 t1、t2、t3 互不相等。

System.out.println(t1 == t4); // true  因为与 int 运算时,会进行自动拆箱。所以 t1、t2、t3 与 t4 相等。

System.out.println(t5 == t6); // true 因为 t5/t6 其值默认指向常量池中的 127 常量。

System.out.println(t5 == t7); //false 因为 t5 是常量,而 t7 是Object实例。

拓展:

与 Integer 类似,String 有两种创建方式。对于使用字面量赋值方式。JVM为了节省空间,会首先查找JVM中是否有对应的字符串常量。如果已经存在,则直接返回该常量或字符串实例对象的地址引用,而无需重新创建对象。对象new创建方式,JVM将添加字面量常量和创建字符串实例并返回实例引用。

注意:

1>String 与 Integer 包装类都是不可变的:

private final int value; // Integer.java

private final char value[]; // String.java

2>常量池的实现有多种,String 与 Integer 的实现方式有区别。 Integer 的常量池直接是 Integer 数组,而 String 在 Java7后移动到堆空间(共享),底层是由 C++ 中的StringTable(类似固定容量的 HashMap)实现,每个 bucket 存储 相同 hash 对应的字符串 列表,效率更高(参考)。

测试1

String a = "we";
String a2 = new String("we");
String b = "we";
String c = "we";
System.out.println(a ==a2.intern());

结果

true

测试2

String a = "1";
String b = "1";
int aHashCode = System.identityHashCode(a);
int bHashCode = System.identityHashCode(b);
System.out.println("\na:" + a + "\nb:" + b);
System.out.print("\naHashCode:" + aHashCode + "\nbHashCode:" + bHashCode); char[] valueChar = new char[0];
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
valueChar = (char[]) value.get(b);
} catch (Exception e) {
e.printStackTrace();
}
valueChar[0] = '2';
String c = "1";
String d = "2";
int cHashCode = System.identityHashCode(c);
int dHashCode = System.identityHashCode(d);
System.out.print("\na:" + a + "\nb:" + b + "\nc:" + c + "\nd:" + d);
System.out.print("\naHashCode:" + aHashCode + "\nbHashCode:" + bHashCode + "\ncHashCode:" + cHashCode + "\ndHashCode:" + dHashCode);

结果

a:1
b:1 aHashCode:476800120
bHashCode:476800120
a:2
b:2
c:2
d:2
aHashCode:476800120
bHashCode:476800120
cHashCode:476800120
dHashCode:1254526270

注意:

Object对象 的 hashCode() 方法与 System.identityHashCode(o) 方法返回结果是一致的。返回相应的 hash码。但 String 类重写了 hashCode() 方法,它是根据以下公式计算:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

导致的 String 对象的 hashCode 与 System.identityHashCode 返回的原值不相等。

为什么要重写 hashCode 方法呢?

1.String Pool 常量池的实现,底层类似 HashMap,一个 hash 对应多个相同字符串。

2.作为HashSet、HashMap等容器的 key 被使用。这些容器依赖于 hashCode 方法的实现(先使用 hashcode 比较,再使用 equals 比较)。

3.根据规范,如果根据 equals(Object) 方法,两个对象是相等(不是相同)的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。所以,根据字符串的 equals 方法的实现(根据字符串值判断相等),hashCode 也需要根据字符串值来返回哈希,以确保对于两个相等的值返回相同的 hashCode。此外,也说明 hashCode 不能是随机的数字,一定要按照相应的实现确立。

不可变的引用类型

在不使用常量池的情况下,new Integer() 返回的是一个引用类型,但是对这个引用实例的修改却并没有改变原来的引用绑定的值,原因是每次修改其实是在重新创建对象并重新绑定。这就是 primitive 类型的实现方式之一。

Integer 的 valueOf 方法 与 常量池(对 String Pool 的部分理解)的更多相关文章

  1. Java String类相关知识梳理(含字符串常量池(String Pool)知识)

    目录 1. String类是什么 1.1 定义 1.2 类结构 1.3 所在的包 2. String类的底层数据结构 3. 关于 intern() 方法(重点) 3.1 作用 3.2 字符串常量池(S ...

  2. 基本数据类型的常量池与String类型常量池解析

    抛出样例: Integer a1  = new Integer(123);        Integer a2  = new Integer(123);        System.out.print ...

  3. 资深架构师教你String 常量池、 String.itern()

    什么是常量 用final修饰的成员变量表示常量,值一旦给定就无法改变! final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池 在Class文件结 ...

  4. Java字符串池(String Pool)深度解析

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 在工作中,String类是我们使用频率非常高的一种对象类型.JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存 ...

  5. Java字符串池(String Pool)深度解析(转)

    出自  http://www.cnblogs.com/fangfuhai/p/5500065.html 在工作中,String类是我们使用频率非常高的一种对象类型.JVM为了提升性能和减少内存开销,避 ...

  6. Java的Integer常量池和String常量池

    1.Integer的常量池 看下面一段代码: package cn.qlq.test; public class ArrayTest { public static void main(String[ ...

  7. JVM体系结构之七:持久代、元空间(Metaspace) 常量池==了解String类的intern()方法、常量池介绍、常量池从Perm-->Heap

    一.intern()定义及使用 相信绝大多数的人不会去用String类的intern方法,打开String类的源码发现这是一个本地方法,定义如下: public native String inter ...

  8. 常量池之String.intern()方法

    JDK7将String常量池从Perm区移动到了Java Heap区.在JDK1.6中,intern方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中的实例.但是在JDK1.7以后,Str ...

  9. [一]class 文件浅析 .class文件格式详解 字段方法属性常量池字段 class文件属性表 数据类型 数据结构

    前言概述  本文旨在讲解class文件的整体结构信息,阅读本文后应该可以完整的了解class文件的格式以及各个部分的逻辑组成含义   class文件包含了java虚拟机指令集 和  符号表   以及若 ...

随机推荐

  1. MAC 开启与关闭SIP

    1. 查看SIP状态 在终端中输入csrutil status,就可以看到是enabled还是disabled. 2. 关闭SIP S1  重启MAC,按住cmd+R直到屏幕上出现苹果的标志和进度条, ...

  2. AXI总线介绍

    原帖地址:https://wenku.baidu.com/view/7c424c17e3bd960590c69ec3d5bbfd0a7956d5b9.html   1.AXI简介 AXI(Advanc ...

  3. 使用python实现深度神经网络 2(转)

    https://blog.csdn.net/oxuzhenyi/article/details/73026796 导数与梯度.矩阵运算性质.科学计算库numpy 一.实验介绍 1.1 实验内容 虽然在 ...

  4. Android TextView中链接(link)点击事件的截取

    布局文件xml <TextView package com.jayce.testlink; import android.net.Uri; import android.os.Bundle; i ...

  5. [C#] 解决Silverlight反射安全关键(SecuritySafeCritical)时报“System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问”的问题

    作者: zyl910 一.缘由 在Silverlight中使用反射动态访问时,经常遇到"System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问-- ...

  6. asp.net mvc 根据浏览器判断,如果是微信浏览器则进行网页授权,否则直接访问

    遇到这个需求,想到的第一点就是,这个肯定是需要写在一个通用的地方.方便调用.一般可以定义个 父类控制器在OnActionExcuting方法执行前写逻辑,先上代码,一边写代码一边讲解: /// < ...

  7. json、数组、html标签的修改删除

    存数组 var aa=[1,2,3]; var sStorage=window.sessionStorage; sStorage.aa=aa; console.log(sStorage.aa); // ...

  8. Python类中的装饰器在当前类中的声明与调用

    [本文出自天外归云的博客园] 我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器.代码如下: class Test(): xx = False def __in ...

  9. bugku的一道图片隐写

    可以看到图片是不完整的就联想到其高宽问题.使用winhex打开 将高里面的01改成11 get flag{He1I0_d4_ba1}

  10. C#字符串、字节数组和内存流间的相互转换

    定义string变量为str,内存流变量为ms,比特数组为bt 1.字符串=>比特数组 (1)byte[] bt=System.Text.Encoding.Default.GetBytes(&q ...