举例:

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. ASP.NET Core使用Razor页面

    ASP.NET Core使用Razor页面 Razor是ASP.NET的页面引擎,在ASP.NET MVC 3以后被广泛使用,我在之前的博客中有所介绍,需要更多了解的朋友请移步[Razor语法] 在A ...

  2. Linux中的普通命令如何以管理员身份运行

    set uid, gid, sticky bit 权限 一个文件都有一个所有者, 表示该文件是谁创建的.同时, 该文件还有一个组编号, 表示该文件所属的组, 一般为文件所有者所属的组.如果是一个可执行 ...

  3. java 使用CXF将wsdl文件生成客户端代码命令java调用第三方的webservice应用实例

    1.先下载cxf包https://download.csdn.net/download/suizhikuo/108112362.解压缩包,通过cmd命令进入到bin目录下(cd cxf\bin的路径) ...

  4. postgresql中使用distinct去重

    select语法 [ WITH [ RECURSIVE ] with_query [, ...] ] SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ...

  5. SSE图像算法优化系列二十五:二值图像的Euclidean distance map(EDM)特征图计算及其优化。

    Euclidean distance map(EDM)这个概念可能听过的人也很少,其主要是用在二值图像中,作为一个很有效的中间处理手段存在.一般的处理都是将灰度图处理成二值图或者一个二值图处理成另外一 ...

  6. 使用Guava的RateLimiter完成简单的大流量限流

    限流的一般思路: 1.随机丢弃一定规则的用户(迅速过滤掉90%的用户): 2.MQ削峰(比如设一个MQ可以容纳的最大消息量,达到这个量后MQ给予reject): 3.业务逻辑层使用RateLimite ...

  7. 分析技术和方法论营销理论知识框架,营销方面4P、用户使用行为、STP,管理方面5W2H、逻辑树、金字塔、生命周期

    原文:五种分析框架:PEST.5W2H.逻辑树.4P.用户使用行为 最近在一点点的啃<谁说菜鸟不懂得数据分析>,相当慢,相当的费脑力,总之,真正的学习伴随着痛苦:) 最初拿到这本书的时候, ...

  8. Mongodb系列- java客户端简单使用(CRUD)

    Mongodb提供了很多的客户端: shell,python, java, node.js...等等. 以 java 为例实现简单的增删改查 pom文件: <dependencies> & ...

  9. AYUI -AYUI风格的 超美 百度网盘8.0

    2017-03-23 19:18:43 (截止到2017-3-23 20:20:33开发结束)体验地址:  http://pan.baidu.com/s/1bX28H4 新增传输列表 ======== ...

  10. Docker安装和使用(转)

    (转)原文地址:https://www.cnblogs.com/xiewenming/p/7903247.html 一,安装Docker 1.1 安装之前保持一个干净的Docker环境 sudo yu ...