1.Integer的常量池

看下面一段代码:

package cn.qlq.test;

public class ArrayTest {
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1.hashCode());
System.out.println(i2.hashCode());
System.out.println(i1 == i2);
System.out.println(i1.equals(i2)); System.out.println("-------------------"); Integer i3 = 1;
Integer i4 = 1;
System.out.println(i3.hashCode());
System.out.println(i4.hashCode());
System.out.println(i3 == i4);
System.out.println(i3.equals(i4)); } }

 

1
1
false
true
-------------------
1
1
true
true

基本知识:我们知道,如果两个引用指向同一个对象,用==表示它们是相等的。如果两个引用指向不同的对象,用==表示它们是不相等的,即使它们的内容相同。

解释:Integer i1 = new Integer(1)的时候是在Java堆中创建一个Integer对象,i1指向堆中的对象,i1与常量池没关系,所以i1==i2为false。

  Integer i3=1;的时候是从常量池中查找值为1的常量,i3指向该常量;Integer i4=1的时候会直接指向该常量,所以 i3 == i4为true。

这就是它有趣的地方了。如果你看去看 Integer.Java 类,你会发现有一个内部私有类,IntegerCache.java,它缓存了从-128到127之间的所有的整数对象。

所以事情就成了,所有的小整数在内部缓存,然后当我们声明类似——

        Integer bInteger=127;

它实际在内部的操作是:

        Integer bInteger=Integer.valueOf(127);

现在,如果我们去看valueOf()方法,我们可以看到:

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

如果值的范围在-128到127之间,它就从高速缓存返回实例。

所以…下面这两个指向同一个对象:

        Integer aInteger=127;
Integer bInteger=127;

我们可以得到true。

现在你可能会问,为什么这里需要缓存?

  合乎逻辑的理由是,在此范围内的“小”整数使用率比大整数要高,因此,使用相同的底层对象是有价值的,可以减少潜在的内存占用。

  然而,通过反射API你会误用此功能。

现在对代码进行反编译和反汇编查看:

package zd.dms.test;

public class ArrayTest {

    public static void main(String[] args) {
Integer i1 = 25;
Integer i2 = new Integer(26);
}
}

反编译:

package zd.dms.test;

public class ArrayTest
{
public static void main(String[] paramArrayOfString)
{
Integer localInteger1 = Integer.valueOf(25);
Integer localInteger2 = new Integer(26);
}
}

反汇编:

C:\Users\Administrator\Desktop>javap -c -v ArrayTest.class
Classfile /C:/Users/Administrator/Desktop/ArrayTest.class
Last modified 2018-9-3; size 384 bytes
MD5 checksum 6535da703ea8fa15da765de7bb03300b
Compiled from "ArrayTest.java"
public class zd.dms.test.ArrayTest
SourceFile: "ArrayTest.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."<init>":()V
#2 = Methodref #3.#16 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#3 = Class #17 // java/lang/Integer
#4 = Methodref #3.#18 // java/lang/Integer."<init>":(I)V
#5 = Class #19 // zd/dms/test/ArrayTest
#6 = Class #20 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 SourceFile
#14 = Utf8 ArrayTest.java
#15 = NameAndType #7:#8 // "<init>":()V
#16 = NameAndType #21:#22 // valueOf:(I)Ljava/lang/Integer;
#17 = Utf8 java/lang/Integer
#18 = NameAndType #7:#23 // "<init>":(I)V
#19 = Utf8 zd/dms/test/ArrayTest
#20 = Utf8 java/lang/Object
#21 = Utf8 valueOf
#22 = Utf8 (I)Ljava/lang/Integer;
#23 = Utf8 (I)V
{
public zd.dms.test.ArrayTest();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0 public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: bipush 25
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: new #3 // class java/lang/Integer
9: dup
10: bipush 26
12: invokespecial #4 // Method java/lang/Integer."<init>":(I)V
15: astore_2
16: return
LineNumberTable:
line 6: 0
line 7: 6
line 8: 16
}

bipush 25     将25推至栈顶

invokestatic  调用Integer的静态方法valueOf(int)方法

astore_1          将栈顶引用型数值存入第二个本地变量

new   调用new Integer(int)

dup   复制栈顶数值(数值不能是long或double类型的)并将复制值压入栈顶

bipush 26     将26推至栈顶

invokespecial  调用Integer的初始化方法(init)

astore_2         将栈顶引用型数值存入第三个本地变量

return   返回,类型是void

补充:

  aload_0                                                            //将this引用推送至栈顶,即压入栈。

总结:Integer i = value;如果i是在-128到127之间,不会去堆中创建对象,而是直接返回IntegerCache中的值;如果值不在上面范围内则会从堆中创建对象。= 走的是valueOf()方法,valueOf(int)会走缓存。

  Integer i2 = new Integer(xxxx);不管参数的value是多少都会从堆中创建对象,与IntegerCache没关系。

  

2.String常量池问题:

package cn.qlq.test;

public class ArrayTest {
public static void main(String[] args) {
String s1 = new String("1");
String s2 = new String("1");
System.out.println(s1.hashCode());//
System.out.println(s2.hashCode());//
System.out.println(s1 == s2);// false
System.out.println(s1.equals(s2));// true System.out.println("-------------------"); String s3 = "1";
String s4 = "1";
System.out.println(s3 == s4);// true
System.out.println(s3.equals(s4));// true
System.out.println(s3.hashCode());//
System.out.println(s4.hashCode());// } }

  String的hashCode不是返回地址,是对其值进行遍历运算。与地址没关系,只对值计算,所以所有的hashCode一样。

  String s1 = new String("1"); 是在堆中创建一个String对象,并检查常量池中是否有字面量为"1"的常量,没有的话在常量区创建"1"并将堆中的对象指向该常量,有的话堆中的对象直接指向"1";

  String s2 = new String("1"); 又在堆中创建一个String对象,并将s2指向该对象,其字面量"1"在前面已经创建,所以不会再创建常量区中创建字符串;

  

  String s3 = "1";   检查常量池中有没有字面量为"1"的字符串,如果没有则创建并将s3指向该常量;有的话直接指向该该常量;

  String s4 = "1"  的时候常量池已经有1,所以不会再创建对象,也就是s3与s4指向同一个对象。

所以我们可以用下面图解解释,String s = new String("xxx")在检查常量池的时候会涉及到堆中创建对象;String s = "x"直接检查常量池,不会涉及堆。

如下图解:

 

一道经典的面试题:new String("abc")创建几个对象?

  简单的回答是一个或者两个,如果是常量区有值为"abc"的值,则只在堆中创建一个对象;如果常量区没有则会在常量区创建"abc",此处的常量区是方法区的运行时常量池(也称为动态常量区)。

  我们需要明白只要是new都会在堆中创建对象。直接String s = "xxx"不会涉及堆,只在常量区检查是否有该常量。

Java的Integer常量池和String常量池的更多相关文章

  1. JAVA中Integer.valueOf, parsetInt() String.valueOf的区别和结果

    先来看段代码 public class IntegerDemo { public static void main(String[] args) { String num = null; System ...

  2. java基础知识回顾之---java String final类 容易混淆的java String常量池内存分析

    /** *   栈(Stack) :存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放  在常量池中). 堆(heap):存 ...

  3. Integer 的 valueOf 方法 与 常量池(对 String Pool 的部分理解)

    举例: public class Test { @org.junit.Test public void intTest() { Integer t1 = 128; Integer t2 = 127; ...

  4. java中Integer常量池

    我们先看一个关于Integer的例子 public static void main(String[] args) { // TeODO Auto-generated method stu Integ ...

  5. Java堆/栈/常量池以及String的详细详解(转)------经典易懂系统

    一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...

  6. JAVA String介绍、常量池及String、StringBuilder和StringBuffer得区别. 以及8种基本类型的包装类和常量池得简单介绍

    一.概述 String是代表字符串的类,本身是一个最终类,使用final修饰,不能被继承. 二.定义方式   方式一:直接赋值法 String str1 = "hello"; 方式 ...

  7. 0024 Java学习笔记-面向对象-包装类、对象的比较、String常量池问题

    包装类 基本类型-->包装类 byte-->Byte short-->Short int-->Integer long-->Long char-->Characte ...

  8. java中的堆、栈、常量池以及String类型的两种声明

    参考自http://blog.sina.com.cn/s/blog_798b04f90100ta67.html http://www.cnblogs.com/fguozhu/articles/2661 ...

  9. java基础进阶一:String源码和String常量池

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8046564.html 邮箱:moyi@moyib ...

随机推荐

  1. java 基本--数据类型转换--001

    小可转大,大转小可能会损失精度(编译出错,需要强制转换)A: byte,short,char -> int -> long -> float ->doubleB: byte,s ...

  2. mysql向上递归&向下递归

    工作记录 向上递归函数test: BEGIN ); ); SET sTemp = '$'; SET sTempChd =cast(rid as CHAR); WHILE sTempChd is not ...

  3. Eclipse闪退解决方案

    1. 找到Eclipse目录下的eclipse.exe,右键点击->发送到桌面快捷方式,然后右键点击快捷方式,选择属性,修改“目标”(或target),其中红色代表eclipse的路径,绿色代表 ...

  4. matlab中prod的使用方法

    B = prod(A) 将A矩阵不同维的元素的乘积返回到矩阵B. 如果A是向量,prod(A)返回A向量的乘积.如果A是矩阵,prod(A)返回A每一列元素的乘积并组成一个行向量B. B = prod ...

  5. 在上传文件时候 request.setCharset对文件名有效 对普通文本域无效 需要通过手动转换编码方式编码

    在上传文件时候 request.setCharset对文件名有效 对普通文本域无效 需要通过手动转换编码方式编码

  6. hdu5575 Discover Water Tank

    题意: 给出个水箱,水箱两侧有无限高的隔板,水箱内有整数高度的隔板将水箱分成n-1份,现在给出m个限制,每个限制表示某个位置的某个高度有水或没水,问最多能同时满足多少个限制.n,m<=2*10^ ...

  7. BZOJ4000 TJOI2015棋盘(状压dp+矩阵快速幂)

    显然每一行棋子的某种放法是否合法只与上一行有关,状压起来即可.然后n稍微有点大,矩阵快速幂即可. #include<iostream> #include<cstdio> #in ...

  8. 洛谷 P2757 [国家集训队]等差子序列 解题报告

    P2757 [国家集训队]等差子序列 题目描述 给一个\(1\)到\(N\)的排列\(\{A_i\}\),询问是否存在 \[1 \le p_1<p_2<p_3<p_4<p_5& ...

  9. ACE主动对象模式(1)

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/11/589168.html 主动对象模式用于降低方法执行和方法调用之间的耦合.该模式描述了另外 ...

  10. Codeforces Round #396 (Div. 2) A B C D 水 trick dp 并查集

    A. Mahmoud and Longest Uncommon Subsequence time limit per test 2 seconds memory limit per test 256 ...