摘要:今天看到了一个的相关问题,解决问题的过程中就想把好好理顺了,总结在这里。查看的构造函数源码可见为了使的线程安全性在构造时得到延续,加了同步块。可见指向同一个对象。
今天看到了一个Java string的相关问题,解决问题的过程中就想把string 好好理顺了,总结在这里。
== 和 equals()== 是判断两个变量是否指向同一个对象,equals()只判断两个字符串内容是否相同
public class Cons { public static void main(String[] args) throws InterruptedException { String s2 = new String("vv"); String s3 = "vv"; System.out.println(s2 == s3);//false System.out.println(s3.equals(s2));//true } }String、StringBuilder和StringBuffer
String和StringBuilder:StringBuilder是可变的,也就是说用StringBuilder创建的字符串你可以随时改变它。
StringBuilder和StringBuffer:StringBuffer是同步的,它是线程安全(thread-safe)的,但效率要比StringBuilder差得多。
查看String的构造函数jdk源码:
public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }
可见 为了使buffer的线程安全性在构造String时得到延续,加了同步块。
String str = new String("vv"); 创建了几个对象?答案:1或2
new String("vv")在堆中创建了1个实例对象,而另1个就是放在常量池中的 "vv" 对象,当然这里的str本身 只是一个引用,放在栈里,用来指向堆中创建出来的对象。所以如果常量池已经有"vv" 对象,就只在堆中创建一个对象;如果还没有,就会放入常量池,然后再在堆中创建一个对象,怎么验证呢?
public class Cons { public static void main(String[] args) throws InterruptedException { String s1 = new String("vv"); String s2 = "vv"; System.out.println(s1 == s2);//false } }
然后用命令行工具( 深入理解Java虚拟机 一书中看的工具)
可见常量池中有一个String 类型的 对象 vv,而且new出来的对象不是指向常量池的那个对象,亦即新创建了一个
注:jdk1.7 以后,虚拟机把存储Java对象的地方定义为堆,其它地方是不会有Java对象的实体的。故常量池不再存储对象实例,而是存储的引用,实际对象还是在堆中,所以有所不同,下文不再赘述。
String str = "vv"; 创建了几个对象?答案:0或1
如果常量池已经有"vv" 对象,就直接返回引用,如果还没有,就会放入常量池,然后返回引用。
public class Cons { public static void main(String[] args) throws InterruptedException { String s1 = "vv"; String s2 = "vv"; System.out.println(s1 == s2);//true } }
可见s1,s2指向同一个对象。
而且常量池也有 vv
String str = "v" + "v";创建了几个对象?答案:0或1
常量字符串是在编译的时候就被确定的,"v"是常量,所以编译时确定
这个代码编译后 与 String str = "vv"; 是一样的
public class Cons { public static void main(String[] args) throws InterruptedException { String s1 = "vv"; String s2 = "v"+"v"; System.out.println(s1 == s2);//true } }
可见 s1,s2 指向同一个对象
String str = s1 + s2;创建了几个对象?答案 视情况而定
“+”连接的两个字符串本身就是字面常量字符串时,如果池中存在这样连接后的字符串,则是不会重新创建对象,而是直接引用池中的字符串对象;如果“+”连接的两字符串中只要有一个是变量,是会产生新的字符串对象。
public class Cons { public static void main(String[] args) throws InterruptedException { String s1 = "ww"; String s2 = "vv"; String s3 = "vvww"; String s4 = "vv"+"ww"; String s5 = "vv"+s1; System.out.println(s3 == s4);//true System.out.println(s3 == s5);//false } }
但是如果变量是常量时,就不同了
public class Cons { public static void main(String[] args) throws InterruptedException { final String s1 = "ww"; String s2 = "vv"; String s3 = "vvww"; String s4 = "vv"+"ww"; String s5 = "vv"+s1; String s6 = s2+s1; System.out.println(s3 == s4);//true System.out.println(s3 == s5);//true } }
但如果先定义final字符串,但未在定义处初始化,那么又不同了,
public class Cons { public static void main(String[] args) throws InterruptedException { final String s1 ; String s2 = "vv"; String s3 = "vvww"; String s4 = "vv"+"ww"; s1 = "ww"; String s5 = "vv"+s1; String s6 = s2+s1; System.out.println(s3 == s4);//true System.out.println(s3 == s5);//false } }
因为s1是在运行过程确定的,所以s5也只能运行时确定;
总结起来, String str=s1+s2 创建几个变量,关键取决于 s1,s2 能否在编译期确定
public class Cons { public static void main(String[] args) throws InterruptedException { String s1 = new String("vv"); String s2 = "v".concat("v"); String s4 = "v"+"v"; String s3 = "vv"; System.out.println(s2 == s3);//false System.out.println(s1 == s3);//false System.out.println(s4 == s3);//true } }
可见concat 产生的变量没有直接引用常量池的对象。
查看jdk8源码
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); }
果然是新创建了一个 String对象。
String 和 Char[]查看jdk源码,知道 String的内部实现就是一个 Char 数组, 说String 不可变,也是因为 这个数组就是一个final 类型的 变量。
未完待续......参考
http://jiangzhengjun.iteye.co...
《深入理解Java虚拟机》
欢迎访问我的个人主页 mageek(mageek.cn)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69999.html
摘要:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。创建一个定长线程池,支持定时及周期性任务执行。 转载请注明原创地址为:http://www.54tianzhisheng.cn/... 线程池 Wiki 上是这样解释的:Thread Pool showImg(https://segmentfault.com/img/remote/146000...
摘要:所有示例代码请见下载于基本概念并发同时拥有两个或者多个线程,如果程序在单核处理器上运行多个线程将交替地换入或者换出内存这些线程是同时存在的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上此时,程序中的每个线程都 所有示例代码,请见/下载于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...
摘要:事件只能携带一个的。例如在上述代码示例中的将所有使用发布事件的地方,全部修改为使用的方法。是否能够编写脚本或者自动化工具,自动化的完成重构工作。实施方案使用注解解析自动生成文件我们都知道,是通过注解来实现的。 欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:吴涛 导语:EventBus 已经火了很长一段时间了。最近我们项目决定引入EventBus,替换我们播放器现在的事...
摘要:问题来源今天与同学聊天,得知他有个任务是抓取同花顺网站上的股票数据,有点兴趣,便做了相关实验。由于时间关系,以上代码只是把数据所在的网页抓取到本地,没有进行解析。 问题来源 今天与同学聊天,得知他有个任务是抓取同花顺网站上的股票数据,有点兴趣,便做了相关实验。 介绍 网站地址:http://q.10jqka.com.cn/ 网站界面:showImg(https://segmentf...
摘要:可空性在中,类型系统区分一个引用是可以容纳可空引用还是不能容纳非空引用。使用可以很方便得将可空转为非空,但可空变量值为,则会。 目录介绍 01.可空性 02.安全调用运算符:?. 03.Elvis运算符:?: 04.安全转换运算符:as? 05.非空断言:!! 06.let函数说明 07.可空类型的扩展 08.Java中判断方式 09.kotlin是否解决NPE 10.kotlin如...
阅读 3054·2021-11-24 09:38
阅读 1313·2021-09-22 15:27
阅读 2936·2021-09-10 10:51
阅读 1446·2021-09-09 09:33
阅读 889·2021-08-09 13:47
阅读 2036·2019-08-30 13:05
阅读 858·2019-08-29 15:15
阅读 2380·2019-08-29 12:21