关于Java中String你可能不知道的那些事
来源:互联网 发布:菜鸟java并发编程书籍 编辑:程序博客网 时间:2024/05/22 11:56
一.String的“==”和“equals”
private static void test1() { Stringa = "a"+"b"+1; Stringb = "ab1"; System.out.println(a== b ); }
上面这段代码的输出结果是true,可能有很多人知道结果,下面来解释下原因。要解释这个问题,我们需要知道这几点。
1.关于"=="和equals是做什么的?
2.a和b在内存中是什么样的?
3.编译时优化方案。
"=="用于匹配内存单元上的内容,在Java语言中,"=="其实就是对比两个内存单元的内容是否一样,简单说就是两个对象的地址是否一样。如果是基本类型,就是直接比较它们的值。如果是引用对象,比较的就是引用的值。引用的值可以被认为是对象的逻辑地址。如果两个引用保存的对象是同一个对象,就返回true。
equals方法,在Object类中被定义的,默认就是"=="的实现,也就是说如果不覆写equals方法,那么默认的equals就是对比对象的地址。
equals方法之所以存在,是希望子类去重写这个方法,实现对比值的功能。类似的String就实现了equals方法。String的equals方法比较的是字符串的值是否相同。
重写equals方法之后一定要重写hashCode方法吗?其实两者之间没有明确规定,但是一般都建议重写hashCode方法,如果不重写会在hashMap,HashSet中添加对象时出现意外的情况。
a和b的内存情况是什么样的?上例中,a和b指的都是同一个对象"ab1"。这是在Java编译器优化后产生的结果,当编译器在编译代码Stringa="a"+"b"+1时会将其编译为String a="ab1"; 为何?因为都是常量,编译器认为这三个常量叠加会得到固定的值,无须运行时在计算,所以这样优化,这样做能一定的提升效率。所以上述a和b其实指的是同一个对象,这也说明了String的"+"操作不一定比StringBuilder.append方法慢。
private static String getA(){ return "a" ; } publicstatic void test2(){ Stringa = "a"; final String c = "a" ; Stringb = a+"b"; Stringd = c+"b"; Stringe = getA()+"b"; Stringcompare = "ab"; System.out.println(b== compare ); System.out.println(d== compare ); System.out.println(e== compare ); }
上面说完之后继续猜这段代码,答案是false,true,false。这段代码对于稍微有点复杂,结果不那么好猜,下面解释下具体原因。
1.第一个输出false,b与compare相比,compare是一个常量,那么b为什么不是呢?因为b=a+"b";a并不是一个常量,虽然a作为局部变量也指向一个常量,但是其引用并未约束是不可以改变的,虽然知道它在这段代码不会改变,但运行时任何事情都会发生,在字节码增强技术面前,当代码发生切入后,就可能发生改变,所以编译器不会做这样的优化。
2.第二个输出true,与第一个的区别在于对叠加的变量c有一个final修饰符,final修饰变量表示这个变量的引用不会改变,所以编译器进行了优化。
3.第三个输出false,这点和第一个相像,编译器无法对方法进行有啊。
接下来讨论下String的"=="和equals的区别,对于"=="只有两个变量的引用指向相同的时候才返回true,即两个String是一个对象,new String()产生的对象是不会相同的,而equals只要两个String的值相同就会返回true,一般我们比较两个字符串是否相等多会使用equals来比较。
附上String重写的equals方法:
public boolean equals(Object anObject ) { if (this== anObject ) { return true ; } if (anObject instanceof String) { StringanotherString = (String) anObject; int n = value .length; if (n == anotherString .value .length ) { char v1 [] = value ; char v2 [] = anotherString .value; int i = 0; while (n -- != 0) { if (v1 [i ] != v2 [i ]) return false ; i++; } return true ; } } return false ; }
二.String的"+"和StringBuilder.append方法
很多书上说StringBuilder.append方法比String的"+"性能快很多,其实也不是绝对的,前面说过String的"+"操作时在拼接常量的时候是可以进行编译器优化的,然而如果字符串不能被编译器优化时,确实应该使用StringBuilder.append方法,String的"+"操作放在循环中,会创建出来无穷多的StringBuilder对象,并且执行append()后再调用toString()来生成一个新的String对象。这些临时对象会占用大量的内存空间,导致频繁的GC,这是String的"+"耗时的主要原因。
附上StringBuilder.append的实现
public Abstract StringBuilder append(Stringstr) { if (str == null)str = "null"; int len = str .length(); ensureCapacityInternal(count + len); str.getChars(0,len,value,count); count += len; return this ; } void expandCapacity( intminimumCapacity ) { int newCapacity = value .length* 2 + 2; if (newCapacity - minimumCapacity< 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays. copyOf(value,newCapacity); }
文章内容参考胖哥的Java特种兵,之前很幸运有机会和胖哥聊过一次,最近打算读读胖哥的书,长长见识。
0 0
- 关于Java中String你可能不知道的那些事
- 关于Java你可能不知道的10件事
- 文档编写那些可能你不知道的事
- 项目实战:关于format(String)你不知道的那些事
- 关于xargs,你可能不知道的
- 关于startActivityForResult你可能不知道的
- 关于iPhone,你可能不知道的
- 关于ActionScript中那些你不知道的事情
- 关于ActionScript中那些你不知道的事情
- 关于ActionScript中 那些你不知道的事情
- JAVA SE中你可能不知道的知识点
- 关于Google你可能不知道的10件事
- 关于static你可能不知道的事
- 关于PHP你可能不知道的10件事
- 关于PHP你可能不知道的10件事
- 关于PHP你可能不知道的10件事
- 关于JavaScript你可能不知道的事 1 - 5
- 关于PHP你可能不知道的10件事
- java语言基础(4)——常量的概述和使用
- POJ 3589 Number-guessing Game G++
- Python学习之[1]——列表
- 程序优化小结
- ElasticSearch - 30分钟快速入门
- 关于Java中String你可能不知道的那些事
- URI和URL的区别
- 主要垃圾回收算法与Hotspot VM垃圾回收器实现
- 34:Swap Nodes in Pairs
- js 监听input
- 环信SDK 头像、昵称、表情自定义和群聊设置的实现 二(附源码)
- 关于启动tomcat的bin文件下setup.bat闪退问题
- 内连接,左外连接(左连接),右外连接(右连接),全连接(交叉连接)
- 【前端】-TypeScript简介