咱们一块儿来看一道关于String的面试题,准确说是改编的面试题!
准备好啦?在放大招以前先来一个小招式java
String s1 = new String("hello"); String s2 = new String("hello");
来,问你们,在这一小段代码中一共建立了几个对象呢?面试
其实这道题并不难,考察的是关于String的重点知识点常量池和字符串优化。数组
这个是经典题了,答案是3个,由于这里的“hello”会在字符串常量池中建立一个,而后在堆中建立2个,因此这道题的答案一共是建立了三个对象。函数
不过我以为更加严谨的一点说法是应该判断在字符串常量池中是否已经存在“hello”这个字符串,不过从这道题的本意来看,事先在字符串常量池中是不存在这个“hello”这个字符串的。优化
再来放一个小招式spa
1 public class TestString { 2 public static void main(String[] args) { 3 4 String s1 = "Java"; 5 String s2 = "从0到1"; 6 String s3 = s1 + s2; 7 String s4 = "Java从0到1"; 8 9 System.out.println(s3 == s4); 10 11 12 } 13 }
对于字符串常量池的位置,字符串常量池在jdk1.6及以前在方法区中,可是在jdk1.7及之后就放在了堆中,咱们如今通常不多使用jdk1.6及以前的版本,所以如今讨论所说的字符串常量池除非特别说明jdk版本,不然默认是在堆中。code
另外对于字符串常量池中存放的是字符串对象,好比String a = “abc”那么在字符串常量池中就存放着这个abc,而这个abc则是一个字符串对象。
对象
哈哈哈,是否是已经开始懵了!blog
经过上面那两题,咱们来悄悄的总结一下接口
1.编译阶段肯定的字符串才会被放到字符串常量池中
2.字符串常量池在堆中
把第二段代码细讲一下吧
咱们知道s1和s2还有s4都会在字符串常量池中,这已经有三个对象了,关键的分析点在这行代码上
1 String s3 = s1 + s2;
对于s3没法在编译阶段肯定下来,因此不管最后的字符串是什么都不会存在字符串常量池中,那么存在哪呢?由于对象建立在堆中,而字符串常量池也在堆中,既然不在字符串常量池中那就是在字符串常量池以外的堆中了,而s3最终的字符串对象是“Java从0到1”,那么也就是说这个字符串在常量池以外的堆中,这是一个对象了,加上以前的三个,这里一共四个了,可是咱们还要分析这个s3是怎么来的,是经过s1和s2相加获得的,由于这个s3最终是在常量池以外的堆中造成的,而s1和s2都是在常量池中,所以会将s1和s2拷贝一份到字符串常量池以外的堆中来造成s3,咱们看下面的一张图来加深理解
因此,这道题的答案是一共建立了6个对象,这道题常常做为公司的面试题,为此还有很多人被绊倒呢
大魔王还找了另一题,一样也是关于String的面试题
程序以下:
1 public class test8 { 2 3 String str = new String("good"); 4 char[] ch = { 'a', 'b', 'c' }; 5 6 public static void main(String args[]){ 7 test8 ex=new test8(); 8 ex.change(ex.str,ex.ch); 9 System.out.print(ex.str+" and "); 10 for(int i=0;i<ex.ch.length;i++) { 11 System.out.println(ex.ch[i]); 12 } 13 } 14 public void change(String str,char ch[]){ 15 str="test ok"; 16 ch[0]='g'; 17 } 18 19 }
解析:
这是java参数传递方式的问题,Java参数,不论是原始类型仍是引用类型,传递的都是副本。
若是参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值。若是在函数中改变了副本的 值不会改变原始的值。
若是参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。若是在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。
a.传递值的数据类型:八种基本数据类型和String(这样理解能够,可是事实上String也是传递的地址,只是string对象和其余对 象是不一样的,string对象是不能被改变的,内容改变就会产生新对象。那么StringBuffer就能够了,但只是改变其内容。不能改变外部变量所指 向的内存地址)。
b.传递地址值的数据类型:除String之外的全部复合数据类型,包括数组、类和接口
ps: String 是 final 的。因此值是不变的。 函数中String对象引用的副本指向了另一个新String对象,而数组对象引用的副本没有改变,而是改变对象中数据的内容.