Thinking in java 之 String

String

  1. 在源码中 String被final修饰 因此String不能被继承
  2. String对象不可变,只要String对象被修改就会被创建新对象
  3. String对象可以被存到常量池,常量池中的对象可以被共享。
String a1 = "abc";
String a2 = "abc";
因为String对象存在常量池,所以a1,a2的地址相同 即a1 == a2 即a1,a2为同一块内存

jdk1.6之前,常量池为与方法区

jdk1.7 常量池位于堆中的一块内存

jdk1.8 从堆中挪出,挪到“元空间” metaspace 类似于方法区

 

String对象的存储:

  1. jdk1.9之前,底层用char[] 数组存储
  2. jdk1.9之后 ,用byte[]

 

cha[]由final修饰 因此String对象不能被更改

对象的比较

== 比较的是对象的地址

equals()  比较的也是对象地址但在String中被重写了,在String中比较的是字符串的内容

当字符串是常量时,即

String a1 = "abc";
String a2 = "abc";

a1 == a2;

当字符串用new时,存储在堆上,即

String a1 = new String("abc");
String a2 = new String("abc");

a1,a2地址不同

内存图

 

<  >  比较

对象不能使用运算符

对象比较分两种:

  1. 自然排序   实现java.lang.Comparable接口.int compareTo(Object obj)
  2. 定制排序  

对象的个数

String a1 = new String("abc");//两个对象
在常量池中有一个final修饰的char[]存储abc,在堆中有一个String对象,对象属性char[]指向常量池中的abc
        String s1 = "hello";
        String s2 = "hello";
        final String s3 = "world";
        String s4 = "helloworld";
        
        String s5 = s1 + "world";
        String s6 = s2 + s3;
        String s7 = "hello" + s3;
        String s8 = "hello" + "world";
        System.out.println(s4 == s5);//false    变量+常量 为变量存储在堆中
        System.out.println(s4 == s6);//false   
        System.out.println(s4 == s7);//true    常量+常量 存储在常量池中
        System.out.println(s4 == s8);//true

可变字符序列

  1. StringBuffer  线程安全
  2. StringBuilder :默认的char[]长度为16,长度不够的话,自动扩容为原来的2倍+2,即34. 线程不安全的

StringBuilder更快,当需要字符串拼接时,编译器会自动引入java.lang.StringBuilder类。

即使编译器会自动引入StringBuilder,也不能随意使用String对象 例如:

public String implicit(String[] fields){

         String result = "";
         for(int i = 0; i < fields.length; i++)
                result += fields[i];
         return result;
}

public String explicit(String[] fields){

        StringBuilder result = new StringBuilde();
        for(int i = 0; i < fields.length; i++)
                result.append(fields[i]);
        return result.toString();
}

 

 在implicit中,虽然系统会自动引入StringBuilder,但是在循环内,每循环一次就会创建一个StringBuilder ,而explicit中从始至终只有一个StringBuilder对象

因此如果为一个类编写toSting()时,如果字符串操作比较简单就可以信赖编译器,但如果要使用循环,那么最好创建一个StringBuilder对象。

posted @ 2020-07-05 08:41  Wei_Wang  阅读(199)  评论(0)    收藏  举报