java基础--04(字符串)

目录

1.字符串 


1.字符串 

       特点:字符串一旦被初始化,就不可以被改变,存放在方法区中的常量池中。

       虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集合,包括直接常(string,integer和 floating point常量)和对其他类型,字段和方法的符号引用。 

       先思考这几个问题:

        String s1 = "abc";

        String s2 = "abc";

        String s3 = new String("abc");

        String s4 = new String("abc");

        

      1.字符串常量池:JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象; 并且可以被共享使用,因此它提高了效率。  由于String类是final的,它的值一经创建就不可改变。  字符串池由String类维护,我们可以调用intern()方法来访问字符串池。intern()方法的作用是在常量池中查找值等于(equals)当前字符串的对象,如果找到,则直接返回这个对象的地址;如果没有找到,则将当前字符串拷贝到常量池中,然后返回拷贝后的对象地址。下面的代码可以解释intern()的功能。       

String a = "123";
String b = new String("123");
String c = new String("123");

System.out.println(a == b); // false
System.out.println(a == b.intern()); // true
System.out.println(c == b.intern()); // false
System.out.println(c.intern() == b.intern()); // true

 

        String s1 = "abc"; 在字符串池创建了一个对象, String s2 = "abc";字符串pool已经存在对象“abc”(共享),所以创建0个对象,累计创建一个对象,此时s1==s2为true这表示指向的是同一个对象,s1.equals(s2)为ture,表示字符串的值相等,字符串中equals比较的是字符串内容是否相同。字符串的equals方法在这里是个特殊,因为Object的equals方法表示的是比较两个对象是否相等,其实内部比较的就是两个对象地址。

     2.关于new String(""),  String s3 = new String("abc");此时创建了两个对象,一个存放在字符串池中,一个存在与堆区中,还有一个对象引用s3存放在栈中,引用s3指向堆区的那个对象。String s4 = new String("abc");此时字符串池中已经存在“abc”对象,所以只在堆中创建了一个对象 ,当然还是有一个引用存在栈中。s3==s4为false, s3和s4栈区的地址不同,指向堆区的不同地址;s3.equals(s4)为true,因为他们都的值相同。s1==s3为false,一个存在常量区,一个存在堆区。s1.equals(s3)为true,因为值相等。

   3.关于常量编译的问题,

String str1 = "ab" + "cd"; //1个对象 

String str11 = "abcd";

由于常量的值在编译的时候就被确定(优化)了,在这里,"ab"和"cd"都是常量,所以编译后str1==str11为true.

  4.String str2 = "ab"; //1个对象

     String str3 = "cd"; //1个对象

     String str4 = str2+str3;

     String str5 = "abcd";

    局部变量str2,str3存储的是存储两个拘留字符串对象(intern字符串对象)的地址。第三行代码原理(str2+str3): 运行期JVM首先会在堆中创建一个StringBuilder类, 同时用str2指向的拘留字符串对象完成初始化,  然后调用append方法完成对str3所指向的拘留字符串的合并, 接着调用StringBuilder的toString()方法在堆中创建一个String对象, 最后将刚生成的String对象的堆地址存放在局部变量str4中。 而str5存储的是字符串池中"abcd"所对应的拘留字符串对象的地址。  str4与str5地址当然不一样了。  内存中实际上有五个字符串对象: 三个拘留字符串对象(str2,str3,str5)、一个String对象和一个StringBuilder对象。str4==str5为false.

  5.JAVA编译器对string + 基本类型/常量 是当成常量表达式直接求值来优化的。

    运行期的两个string相加,会产生新的对象的,存储在堆(heap)中

      String str6 = "b";

     String str7 = "a" + str6;

     String str67 = "ab";

     System.out.println("str7 = str67 : "+ (str7 == str67));为false  str6为变量,在运行期才会被解析。

    常量变量的编译优化:

     final String str8 = "b";

     String str9 = "a" + str8;

     String str89 = "ab";

     System.out.println("str9 = str89 : "+ (str9 == str89));  由于str8是基本类型或常量,java编译器编译的时候把他当成常量表达式直接求值优化的。所以str9==str89为true.

     6.对final用法的理解:

     

      a.append("222");// 编译通过

    可见,final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。 

   7.深入理解String的用法:

    在执行到双引号包含字符串的语句时,如String a = "123",JVM会先到常量池里查找,如果有的话返回常量池里的这个实例的引用,否则的话创建一个新实例并置入常量池里。如果是 String a = "123" + b (假设b是"456"),前半部分"123"还是走常量池的路线,但是这个+操作符其实是转换成[SringBuffer].Appad()来实现的,所以最终a得到是一个新的实例引用,而且a的value存放的是一个新申请的字符数组内存空间的地址(存放着"123456"),而此时"123456"在常量池中是未必存在的。而new出来会在常量池中。

要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象

 8.StringBuffer与StringBuilder的区别,它们的应用场景是什么?

        StringBuffer:字符串变量(线程安全)

   StringBuilder:字符串变量(线程不安全)

 9.对字符串不可变性的深入理解:

  无论是sub操、concat还是replace操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

在这里要永远记住一点:“String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”

 Java中的常量池,实际上分为两种形态:静态常量池运行时常量池
所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

   

String a = "chenssy";
String b = "chenssy";
String c = new String("chenssy");

String常用的方法compareTo

  语法:Str1.compareTo(Str2);

    其返回的是一个int类型值。若Str1等于参数字符串Str2字符串,则返回0;若该Str1按字典顺序小于参数字符串Str2,则返回值小于0;若Str1按字典顺序大于参数字符串Str2,则返回值大于0。

java中的compareto方法,返回参与比较的前后两个字符串的asc码的差值,看下面一组代码

    String a="a",b="b";

    System.out.println(a.compareto.b);

    则输出-1;

    若a="a",b="a"则输出0;

    若a="b",b="a"则输出1;

   

   单个字符这样比较,若字符串比较长呢??

   若a="ab",b="b",则输出-1;

   若a="abcdef",b="b"则输出-1;

   也就是说,如果两个字符串首字母不同,则该方法返回首字母的asc码的差值;

  如果首字母相同呢??

  若a="ab",b="a",输出1;

  若a="abcdef",b="a"输出5;

  若a="abcdef",b="abc"输出3;

  若a="abcdef",b="ace"输出-1;

   即参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的asc码差值,如果两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值

参考博文:

深入理解Java:String - ^_TONY_^ - 博客园  博大精深的一篇博客

深入理解Java中的String - 平凡希 - 博客园

java中比较字符串的大小(compareTo方法的使用)_ymony的博客-CSDN博客_比较字符串的大小

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值