0
点赞
收藏
分享

微信扫一扫

从零开始的JDK之旅 day02

千行 2021-09-25 阅读 63
日记本

字符串(类)

为什么String类型 和 基本数据类型用+号拼接会变成String类型?
"+"连接符的原理:
String str1 = "hello";
int i = 10;
System.out.println(str1+i);
上面的代码中,反编译之后的结果是:
String str1 = "hello";
byte byte0 = 10;
System.out.println((new StringBuilder()).append(str1).append(byte0).toString());
"+" 连接符的效率问题:
使用 "+" 连接符,JVM会隐饰的创建StringBuilder对象,这种方式大部分情况不会造成效率的随时,
但是如果在大量循环处理时要注意。
        for (int j = 0 ;j < 1000 ; j++){
            System.out.println(str1+i);
            // 其实就是
            System.out.println(new StringBuilder().append(str1).append(i).toString());
        }
当循环次数多的时候,必然会创建很多StringBuilder对象,这样大量的StringBuilder对象在堆中存储,
必然造成效率的损失,当这种情况应该在循环外创建一个StringBuilder对象,手动调用append方法拼接。
        StringBuilder sb = new StringBuilder();
        for (int k = 0 ;k < 1000 ; k++){
            System.out.println(sb.append(str1).append(i).toString());
        }
还有一种特殊情况:就是当"+"连接符两边均为编译器确定的字符串常量时,编译器会进行优化,
直接将两个字符串拼接好。
System.out.println("Hello" + "World");
/**
 * 反编译后
 */
System.out.println("HelloWorld");
        /* 对于final修饰的变量,他在编译时被解析为一个常量值的一个本地拷贝,存储        
           在自己的常量池中或嵌入到他的字节码流中 */
        /* 所以此时s0 和 s2 的内存地址是一样的 返回true */
        String s0 = "ab";
        // 打印内存地址
        System.out.println(System.identityHashCode(s0));//1112280004
        final String s1 = "b";
        String s2 = "a"+s1;
        System.out.println(System.identityHashCode(s2));//1112280004
        System.out.println(s0 == s2);
        /* 这里虽然s1被final修饰,但是他的值是方法返回的,无法在编译期间确定,
           所以s0 和 s2 的内存地址不同 */
        String s0 = "ab";
        System.out.println(System.identityHashCode(s0));//1112280004
        final String s1 = getStr();
        String s2 = "a"+s1;
        System.out.println(System.identityHashCode(s2));//1013423070
        System.out.println(s0 == s2);
字符串常量池

java内存分配中总共有三种常量池:Class常量池,运行时常量池,字符串常量池。
每当新创建字符串的时候,JVM首先会去字符串常量池中查找字符串是否存在,如果存在,直接返回该实例的引用,如果不存在就创建该实例,并放入常量池中,并返回该实例的引用。由于String字符串的不可变行,字符串常量池中一定不存在两个相通的字符串。

String类的值是不可改变的?

String类的值存储在被final 修饰的 char数组中,并且没有提供修改数组的方法,所以说String的值是不可变得。但是真的不能改变吗?
其实可以通过反射区改变String类的value值:

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        String str = "abc";
        System.out.println(str); // abc
        /* 根据字段名拿到value这个字段 */
        Field fieldValue = String.class.getDeclaredField("value");
        /* 因为value是 private的 所以修改访问权限 */
        fieldValue.setAccessible(true);
        /* 获取str对象的 value值 */
        char[] value = (char[]) fieldValue.get(str);
        /* 改变第一个字符 */
        value[0] = 'x';
        System.out.println(str);// xbc
    }

不过在代码中几乎是不可能会用反射去修改类的值的,所以String的值还是不可变得~

String类的方法
  • join()方法:内部使用StringJoiner对象来拼接字符创,如果不需要指定开头和结尾的话使用join字符串拼接更方便。
        String join = String.join("/", "a", "b", "c");
        System.out.println(join);// a/b/c
举报

相关推荐

从零开始的JDK之旅 day01

从零开始的JDK之旅 day03

Day02

day02

vue day02

uniapp—day02

shell day02

0 条评论