聊一聊String那些事情

消失了一段时间,也不知道在远方的电脑面前是否有人惦记着我。–pluto

在Java里面String肯定是最常用的数据类型没有之一,但是你真的了解String这个类吗?

String类是一个final修饰的,这表明String是一个不能被继承的类。我当初还傻乎乎想过要继承String,编译器报错,网上查了一查才发现String是final修饰,如果当时小手一点看一看源码,是不是就可以节省一下上网百度的时间了。

在Java8里面String类有8种构造方法,其中两种被标记过时。这里重点讲讲这个构造方法String(String original),源码实现如下:

    public String(String original) {
        //把原对象的value和hash赋值给新对象
        this.value = original.value;
        this.hash = original.hash;
    }

可能你们不是很理解为什么要单独说这么一个构造方法,这一点后续会有讲解,看下面这段代码

    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "123";
        String s3 = new String("123");
        if (s1 == s2)
            System.out.println("1");
        if (s2 == s3)
            System.out.println("2");
    }

运行结果如图
这里写图片描述
有没有一点小惊讶?我第一次看见的时候感觉很不可思议的,感觉书上说法坑我,因为书上说字符串的比较要用equals()这个方法,不能使用==进行比较。

真的理解这段代码其实也不是很难,至少我看了《深入理解Java虚拟机》(周志明著)这本书过后,我是觉得这个问题理解起来没有任何难度的。如图(图有点丑,请不要介意)
这里写图片描述
在用引号创建字符串的时候,JVM会先在字符串常量池去寻找有没有对应的字符串,如果有就返回引用,没有就新建一个字符串并且放入字符串常量池。所以这里的s1==s2是成立,但是s2==s3就不成立,因为这里已经不是同一个对象了。为了验证我的说法,我修改了一下代码

    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "123";
        String s3 = new String("123");
        String s4 = getString("123");
        if (s4 == s2) {
            System.out.println("3");
        }

    }
    public static String getString(String s) {
        return s;
    }

运行结果就是3,没有任何悬念。是不是觉得自己棒棒?感觉又懂了好多东西?我们来一组代码(这是Java7开始支持的)

    public static void main(String[] args) {
        String s1 = "123";
        String s3 = new String("123");
        switch (s3) {
            case "123":
                System.out.println("123");
                break;
            default:
                System.out.println("321");
                break;
        }
    }

猜猜结果是123还是321呢?我猜你是不知道,我上面已经提示过了。结果是123,我猜你可能还是不懂为什么。看一段编译结果代码

    public static void main(String[] var0) {
        String var1 = "123";
        String var2 = new String("123");
        byte var4 = -1;
        //选择的是hash值
        switch(var2.hashCode()) {
        case 48690:
            //进行内容比较
            if (var2.equals("123")) {
                var4 = 0;
            }
        default:
            switch(var4) {
            case 0:
                System.out.println("123");
                break;
            default:
                System.out.println("321");
            }

        }
    }

看到上面的编译结果,结合我说的String(String original)这个构造方法,你是不是明白了什么?首先编译器会自动定义一个byte var4=-1,然后对我输入的字符串的hashCode()进行比较,接着对case中的hash值进行内容比较,重新给var4变量赋值,最后执行default里面的语句。这个判断方式和上面说的String(String original)的构造方式不谋而合。是不是觉得打开眼界?我们继续最后一波科普。

    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "1";
        String s3 = "23";
        String s4 = "1" + "23";
        String s5 = s2 + s3;
        if (s1 == s4)
            System.out.println("1");
        if (s1 == s5) {
            System.out.println("2");
        }
    }

直接上结果截图吧
这里写图片描述
看到现在,你晕了吗?为什么只打印输出了一个结果?来一波编译结果源码分析

    public static void main(String[] var0) {
        String var1 = "123";
        String var2 = "1";
        String var3 = "23";
        //这里是重点,和java源码已经不一样了
        String var4 = "123";
        //这里用的是StirngBuilder,具体看下图
        String var5 = var2 + var3;
        if (var1 == var4) {
            System.out.println("1");
        }
        if (var1 == var5) {
            System.out.println("2");
        }

    }

再来一张更直观的
这里写图片描述
看看实现细节,String s4 =”1”+”23” 被直接解释成String s4=”123”,而String s5=s2+s3 这个被转换成StringBuilder调用了两次append()方法,最后调用的toString()方法来返回的。讲到这里,你对上面的结果能理解了吗?

看完这篇文章,你有没有恍然大悟的感觉?

如有疑问,欢迎留言

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值