zoukankan      html  css  js  c++  java
  • java中String常量的存储原理

    相关题目(运行结果在代码注释后面)

    1、

    package StringTest;
    
    public class test1 {
    
    public static void main(String[] args){
    String a = "a1";//“a1”在编译的时候就能确定,所以编译的时候,a1被放进了常量池中,同时a指向常量池中的a1对象
    String b = "a"+ 1;//a和1这两个常量都能在编译时确定,所以他们相加的结果也能确定,因此编译器检查常量池中是否有值为a1的String对象,发现有了,因此b也指向常量池中的a1对象
    System.out.println(a==b);//==判断的是a和b是否指向同一个对象,也就是同一块内存区域
    }//true
    } 

    2、

    package StringTest;
    
    public class test2 {
    public static void main(String[] args){
    String a = "ab";
    String bb = "b";
    String b = "a"+ bb; //编译器不能确定为常量
    System.out.println(a==b);
    }//false
    } 

    3、

    package StringTest;
    
    public class test3 {
    public static void main(String[] args){
    String a = "ab";
    final String bb = "b";
    String b = "a"+ bb; //bb加final后是常量,可以在编译器确定b
    System.out.println(a==b);
    }//true
    
    } 

    4、

    package StringTest;
    
    public class test4 {
    public static void main(String[] args){
    String a = "ab";
    final String bb = getBB();
    String b = "a"+ bb;//bb是通过函数返回的,虽然知道它是final的,但不知道具体是啥,要到运行期才知道bb的值
    System.out.println(a==b);
    }//false
    private static String getBB(){ return "b"; }
    } 

    5、

    package StringTest;
    
    public class test5 {
    private static String a = "ab";
    public static void main(String[] args){
    String s1 = "a";
    String s2 = "b";
    String s = s1 + s2;//+的用法
    System.out.println(s == a);
    System.out.println(s.intern() == a);
    //intern的含义(intern()用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用,否则,在常量池中加入该对象,然后 返回引用) }//flase true }

    6、

    package StringTest;
    
    public class test6 {
    private static String a = new String("ab");
    public static void main(String[] args){
    String s1 = "a";
    String s2 = "b";
    String s = s1 + s2;
    System.out.println(s == a);
    System.out.println(s.intern() == a);
    System.out.println(s.intern() == a.intern());
    }//flase false true
    } 

    详解

    1、String使用private final char value[]来实现字符串的存储,也就是说String对象创建之后,就不能再修改此对象中存储的字符串内容,所以说String类型是不可变的(immutable);

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

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

         new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址

      (注意,此时不需要从堆中复制到池中,否则,将使得堆中的字符串永远是池中的子集,导致浪费池的空间)

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

    5、使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;

    6、关于equals和==

    (1)对于==,如果作用于基本数据类型的变量(byte,short,char,int,long,float,double,boolean ),则直接比较其存储的"值"是否相等;如果作用于引用类型的变量(String),则比较的是所指向的对象的地址(即是否指向同一个对象)。

    (2)equals方法是基类Object中的方法,因此对于所有的继承于Object的类都会有该方法。在Object类中,equals方法是用来比较两个对象的引用是否相等,即是否指向同一个对象。

    (3)对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等。

    7、String、StringBuffer、StringBuilder的区别

    (1)可变与不可变:String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象(其内部的字符数组长度可变)。

    (2)是否多线程安全:String中的对象是不可变的,也就可以理解为常量,显然线程安全。StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是非线程安全的。

    (3)String、StringBuilder、StringBuffer三者的执行效率:
    StringBuilder > StringBuffer > String 当然这个是相对的,不一定在所有情况下都是这样。

    比如String str = "hello"+ "world"的效率就比 StringBuilder st  = new StringBuilder().append("hello").append("world")要高。因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:
    当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
    当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。

  • 相关阅读:
    UG二次开发-CAM-获取修改路径参数
    多线程01
    MFC的对话框使用Scintilla
    CATIA的后处理
    win32窗体中使用Scintilla窗体
    string的reserve和resize
    前端宝典
    MarkDown学习
    JAVA中构造方法总结
    IDEA中maven和tomcat的配置
  • 原文地址:https://www.cnblogs.com/wyhb008/p/10594819.html
Copyright © 2011-2022 走看看