zoukankan      html  css  js  c++  java
  • String是个啥?

    String是个啥?

      字符串?不可变字符串?今天想起来这个又意思的东西,所以来记录一下。我们说String是不可变字符串,那他就真的不可变吗?

    public class StringDemo {
        public static void main(String[] args) {
            String s = " a b ";
            s.trim();
            System.out.println("-" + s + "-");
        }
    }

    输出:- a b -
    空格没有被删除

    public class StringDemo {
        public static void main(String[] args) {
            String s = " a b ";
            s = s.trim();
            System.out.println("-" + s + "-");
        }
    }

    输出:-a b-
    空格被删除

    public class StringDemo {
        public static void main(String[] args) {
            String s = " a b ";
            String ss = s.trim();
            System.out.println("-" + ss + "-");
        }
    }

    输出:-a b-
    空格被删除
    public class StringDemo {
        public static void main(String[] args) {
            String s = " a b ";
            String ss = s.trim();
            System.out.println("-" + s + "-");
        }
    }

    输出:- a b -
    空格没有被删除

      我蒙蔽了,来理一理,先看一看String的源码:

    public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
        private final char value[];
    
        private int hash; 
        
        private static final long serialVersionUID=-6849794470754667710L;
        ......
    public String trim() {
            int len = value.length;
            int st = 0;
            char[] val = value;    /* avoid getfield opcode */
    
            while ((st < len) && (val[st] <= ' ')) {
                st++;
            }
            while ((st < len) && (val[len - 1] <= ' ')) {
                len--;
            }
            return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
        }

     String类为什么被称为不可变字符串呢?是因为类上面加了final还是value[]数组上面加了final呢?还是因为String类没有提供可变的方法呢?我们不妨利用反射拿到这个value数组试一试。

    public class StringDemo {
        public static void main(String[] args) throws Exception {
            String s = " a b ";
            Class clazz = s.getClass();
            Field f = clazz.getDeclaredField("value");
            f.setAccessible(true);
            char[] cs = (char[])f.get(s);
            cs[1] = 'A';
            System.out.println(s);
        }
    }
    输出: A b 

      这说明它是可变的啊,final只不过是约束了变量所指向的地址不能变,并不是说地址段的内容不能变,也就说,虽然value数组使用final修饰,但这只是定义了我value变量指向的地址不能变,但是地址段本身的内容(数组的内容)是可变的。

      String 是final类,也就是说,一旦定义了String类型的变量,那么变量本身所指向的地址就不能变了。但是String变量指向的地址的内容可变吗?这你就得注意点了,String类型变量和普通类型变量以及引用类型变量都有区别,虽然String类型变量是引用类型,但他还有另一个身份,String类型的变量还是个常量!既然是常量,那JVM就会把它区别对待,把它保存在方法区的常量池中。

      当s.trim()时,trim()方法入栈,在本方法的栈针中,定义了一个新的char类型数组val,并指向保存原字符串信息的char数组value,但由于数组是基本类型的,所以并没有传引用,而是直接把数组的内容复制给了新的数组val,经过循环操作完成方法后返回一个字符串,但是这个字符串是个常量,JVM如果发现这个常量在常量池中不存在,就会把他保存在常量池中,注意了:这个新的字符串常量和原字符串常量在不同的内存块。但是由于s是final修饰的,所以s并不能改变地址指向新的字符串常量,所以s的输出的值不变,与s不同的是,String ss = s.trim()刚好站了出来,说:我来指向它!于是,ss的输出的值就成了新的字符串常量。如果没有ss指向那个新的常量,那他就可能过会儿被GC了。

  • 相关阅读:
    Codeforces 834D The Bakery
    hdu 1394 Minimum Inversion Number
    Codeforces 837E Vasya's Function
    Codeforces 837D Round Subset
    Codeforces 825E Minimal Labels
    Codeforces 437D The Child and Zoo
    Codeforces 822D My pretty girl Noora
    Codeforces 799D Field expansion
    Codeforces 438D The Child and Sequence
    Codeforces Round #427 (Div. 2) Problem D Palindromic characteristics (Codeforces 835D)
  • 原文地址:https://www.cnblogs.com/superlsj/p/11992163.html
Copyright © 2011-2022 走看看