常量池 字符串常量池

1、String 常量池 为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。 Note:常量池在java用于保存在编译期已确定的,

1、String 常量池

为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。

Note:常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式。

2、True OR False

首先得看下 几个对象???

相信很多 玩java的都做过类似String s = new String("abc")这个语句创建了几个对象的题目。 这种题目主要就是为了考察对字符串对象的常量池掌握与否。其实上述的语句中是创建了2个对象:

第一个对象是"abc"字符串存储在常量池中

第二个对象在JAVA Heap中的 String 对象。这里不要混淆了s是放在栈里面的指向了Heap堆中的String对象

下面再看:

String str1 = new String("abc");
String str2 = "abc";

这里是两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。运行时期创建
而第二种是先在栈中创建一个对String类的对象引用变量str2,然后通过符号引用去字符串常量池里找有没有"abc",如果没有,则将"abc"存放进字符串常量池,并令str2指向”abc”,如果已经有”abc” 则直接令str2指向“abc”。“abc”存于常量池在编译期间完成

还有几个经常考的面试题: 
  String s1 = new String(“s1”) ;
  String s2 = new String(“s1”) ;
  上面创建了几个String对象?
  答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.(用new创建的每new一次就在堆上创建一个对象,用引号创建的如果在常量池中已有就直接指向,不用创建)

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。

下面就是用几个例子说明来说明一下

​ 例1

  String s1 = "sss111";
  String s2 = "sss111";
  System.out.println(s1 == s2); //结果为true

例2

  String s1 = new String("sss111");
  String s2 = "sss111";
  System.out.println(s1 == s2); //结果为false

例3

    String s0 = "111";              //pool
    String s1 = new String("111");  //heap
    final String s2 = "111";        //pool
    String s3 = "sss111";           //pool
    String s4 = "sss" + "111";      //pool
    String s5 = "sss" + s0;         //heap 
    String s6 = "sss" + s1;         //heap
    String s7 = "sss" + s2;         //pool
    String s8 = "sss" + s0;         //heap

    System.out.println(s3 == s4);   //true

    System.out.println(s3 == s5);   //false

    System.out.println(s3 == s6);   //false

    System.out.println(s3 == s7);   //true

    System.out.println(s5 == s6);   //false

    System.out.println(s5 == s8);   //false

结果上面分析,总结如下:

1.单独使用**""引号创建的字符串都是常量,编译期就已经确定存储到Constant Pool**中;

2,使用new String("")创建的对象会存储到heap中,是运行期新创建的;

3,使用只包含常量的字符串连接符如**“aa” + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中,String pool中存有“aaaa”**;

不会存有“aa”

4,使用包含变量的字符串连接符如**“aa” + s1创建的对象是运行期才创建的,存储在heap**中;只要s1是变量,不论s1指向池中的字符串对象还是堆中的字符串对象,运行期s1 + “aa”操作实际上是编译器创建了StringBuilder对象进行了append操作后通过toString()返回了一个字符串对象存在heap上。

​ 5 , String s2 = “aa” + s1; String s3 = “aa” + s1; 这种情况,虽然s2,s3都是指向了使用包含变量的字符串连接符如"aa" + s1创建的存在堆上的对象,并且都是s1 + “aa”。但是却指向两个不同的对象,两行代码实际上在堆上new出了两个StringBuilder对象来进行append操作。在Thinking in java一书中285页的例子也可以说明。

​ 6,对于final String s2 = “111”。s2是一个用final修饰的变量,在编译期已知,在运行s2+"aa"时直接用常量“111”来代替s2。所以s2+"aa"等效于**“111”+ “aa”。在编译期就已经生成的字符串对象“111aa”存放在常量池**中。

知秋君
上一篇 2024-08-23 18:48
下一篇 2024-08-23 18:12

相关推荐