String求求你别秀了

 小鲁班今年计算机专业大四了,在学校可学了不少软件开发的东西,也自学了一些JAVA的后台框架,踌躇满志,一心想着找个好单位实习。当投递了无数份简历后,终于收到了一个公司发来的面试通知,小鲁班欣喜若狂。

  到了人家单位后,前台小姐姐给了小鲁班一份笔试题目,要求在一个小时内完成,小鲁班双手接过题目后,粗略的看了一下题目,心里暗喜,嘻嘻这个还不简单。一顿操作猛如虎,做完了感觉也没什么错误。就交卷了,等待片刻后,小姐姐亲切的说需要一周内等通知哦。于是呢,小鲁班就回去耐心的等待了。可是半个月都快过去了,什么消息都没有,小鲁班就纳闷了,明明我做的挺好的呀,为什么连面试的机会都不给我。

  小鲁班于是找到了他表哥鲁班大师,正准备吐槽这件事,并把一些当时面试的题目重现了一些,并把自己对题目的理解也说了遍,鲁班大师一看他填的答案就开始嘲讽他,前5道题目关于String类的判断题可真是完全避开了正确答案呀,而且后边的题目也是大部分都是错了,人家当然不给你机会呀。

  小鲁班你可要虚心学习了,就拿下边最简单的一题来说,你怎么连==对于非基本数据类型是比较引用而不是比较值的都不知道呀 

复制代码
String str1 = new String("AA"); String str2 = new String("AA"); System.out.println(str1 == str2); 这里的正确答案是false
复制代码

 

  鲁班大师:感觉你的JAVA基础不咋地呀,你说说你在学校学习你所掌握的关于String类的知识点,你表哥今天有空帮你恶补一波吧。

  小鲁班垂头丧气的说到:

  • String类有如下这些特点

  1. String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。
  2. String类其实是通过char数组来保存字符串的。
  3. String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象。

 

  鲁班大师:嗯,不错嘛,那有没有深入一点的理解呢,比如关于字符串常量池

  小鲁班:这个我~~忘记了!

  鲁班大师:没关系,那你得认真听讲了

  小鲁班:emmm

 

  • 字符串常量池

  1. 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
  2. 字符串池的出现避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。

  String a="AA";

  String b="AA";

  String c=new String("AA");

  a、b和堆中创建的AA都是指向JVM字符串常量池中的"AA"对象,他们指向同一个对象。

  new关键字一定会产生一个对象AA,同时这个对象是存储在堆中。所以String c=new String("AA")这一句应该产生了两个对象:保存在方法区中字符串常量池的AA和保存堆中AA。但是在Java中根本就不存在两个完全一模一样的字符串对象。故堆中的AA应该是引用字符串常量池中AA。所以c、堆AA、池AA的关系应该是:c--->堆AA--->池AA。

  虽然a、b、c是不同的引用,但是从String的内部结构我们是可以理解上面的。String c = new String("AA");虽然c的内容是创建在堆中,但是他的内部value还是指向JVM常量池的AA的value,它构造AA时所用的参数依然是AA字符串常量。所以a==b是ture,因为内存地址是一样的 a==c是false,因为c的内存地址指向是在堆中new的是新的地址,而不是在常量池的地址。

  鲁班大师又问了:我看你还挺懵的,你知道==和equals吗

  小鲁班:这个我知道。

  

  • 对于==,如果作用于基本数据类型的变量(byte,short,char,int,long,float,double,boolean ),则直接比较其存储的"值"是否相等;如果作用于引用类型的变量(String),则比较的是所指向的对象的地址(即是否指向同一个对象)。
  • 对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等。

  鲁班大师:嗯,答的不错,但是要应付一些面试题,你还要知道这些。

  1. 单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
  2. 使用new String("")创建的对象会存储到heap中,是运行期新创建的;
  3. 使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
  4. 使用包含变量(引用)的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
  5. 但是如果s1是被final修饰的话,则s1是属于常量。结果存在String Pool,但是 final修饰的是一个方法返回的值也是在编译器确定。

  好了,这些你都知道了,那你把刚那份题目在做一次看看

  

复制代码
String str1 = "aaa"; String str2 = "aaa"; System.out.println(str1 == str2);// true 因为String有常量池 String str3 = new String("aaa"); String str4 = new String("aaa"); System.out.println(str3 == str4);// false 可以看出用new的方式是生成不同的对象,比较堆上的         String s0="helloworld";   String s1="helloworld"
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信