最近在找工作,基本都是java开发的方向,很多笔试、面试题都是围绕String类对象展开的,花样很多,但是万变不离其中,掌握了基本的原理,无论怎么变,实质都是一样的。下面总结一下关于String的基本知识点:
(一)String是final的
可能我们很多人遇到过这个问题final关键字有什么作用,其中一个回答就是final修饰类表示不可继承。大家有没有仔细想过为什么呢?我也曾花了一点时间google,网上的争论很多。有个解答很有意思:To computer languages or natural languages, I always prefer to ask what and how instead of why. Even though I know there are a lot of good and bad reasons behind them. The good ones make the language vital and successful, the bad ones make future improvement and replacement possible. Languages (natural and programming languages included) are not rigorous science, a lot of human factors are involved. To programming languages, another factor is the cost. This is a more philosophical and time-efficient decision of mine. You can make yours different than mine, of course.有些东西我们只需要知道是什么和如何做就可以了,至于为什么,在它后面可能暗藏深刻的哲学道理,超过了编程语言的本身,是语言创建者的一个思想的表达(或者是本身有bug,不得已而为之,呵呵)。
但是还是找到一些ms正确的原因:
第一,final修饰类表示不可被继承,final类的所有方法都是final的:这有两个好处:一是编译器会对final的方法进行内联的操作(Think in JAVA中表示这不是必须的)提高运行效率;二是防止恶意用户修改String类的某些方法,如length()
第二,让一个类无法继承,表明这个类没有什么可以改进或扩充的啦,可能开发者认为这个类已经足够了,不需要用户进行特别的改进
第三,无从证实,有解释说如果String类不是final,可能会导致恶意用户修改系统System的参数,如访问控制权限,它的所有方法都是可以改变的,会导致不安全。
和本文相关的我认为你得认识到final会导致对于String的操作产生什么现象,即任何对String的修改都会产生新的对象,但是如果修改后的对象和原来的对象一样,则直接返回原来的对象。
(二)如何构建String对象
1.首先String是个类,可以使用new直接创建:String s = new String("hello");
这里发生的一切和其他一切对象的生成一样
step 1:载入String的class文件,将相应类型信息放入方法区,此时字符串常量“hello”已经存入该语句所在类的常量池中
step 2:堆上创建一个String的引用对象s,将其压入栈中
step 3:寻找"hello"存储的位置
step4:调用new,按照String指定的构造函数创建对象,此时将"hello"传给了这个新生成的字符串对象
step5:将这个新生成的字符串对象的地址传给s
这个过程的指令集如下:
- new java.lang.String
- dup
- ldc <String "hello" >
- invokespecial java.lang.String(java.lang.String)
- astore_1 [s]
- return
2.不同于一般的类,String还可以像基本类型那样进行初始化:String s = "hello";
这里的s直接存储的就是"hello"在堆中(常量池)的地址
指令集如下:
- ldc <String "Hello world" >
- astore_1 [s]
- return
有了上面两个介绍,其实大家就明白了,问题的关键就是String s这个引用存储的是什么?是地址,是谁的地址?
(三)常见问题及解答
equals()比较的是值,==比较的是地址,请牢记
String sa = new String("hello");
String sb = new String("hello");
sa == sb;//false,sa和sb分别存放了两个字符串对象的引用及地址,肯定不同
String sa = "hello";
String sb = "hello";
sa == sb;//true,sa和sb存放的是字符串常量在常量池中的地址,是一样的
String sa = "hello "+"world";
String sb = "hello world";
sa == sb;//true,编译器会直接在编译时对字符串常量进行连接,因此sa和sb存储的是一样的,常量池中只有"hello world"
String s1 = "hello ";
String s2 = "world";
String sa = s1 + s2;
String sb = "hello world";
sa == sb;//false,java程序运行时,对于字符串连接操作符‘+’,是将其转为StringBuilder()类或StringBuffer()类的append()方法进行连接,相当于new了一个新的字符串对象
"a".toLowerCase()=="a";//对于字符串的操作如果结果不变,则会返回原来的字符串,所以相等
"a"+"b".toLowerCase()=="ab";//false,参考上例对'+'操作符在运行时的解释
以上是我参加众多笔试面试遇到的关于String对象的问题,以及我在网上查找的认为对的解释说明进行的总结,如果有什么不对请指出。