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了。

  • 相关阅读:
    混合使用UITabBarController和UINavigationController
    基本组件的使用——UITabBarController
    基本组件的使用——UINavigationController
    ios应用程序结构
    让我想起了以前
    如何利用新浪博客做外链1
    如何利用新浪博客做外链
    网站优化之如何更新发布文章
    无线淘宝有600多项加权项
    用代理服务器直接注册小号刷单
  • 原文地址:https://www.cnblogs.com/superlsj/p/11992163.html
Copyright © 2011-2022 走看看