> 文章列表 > Java之关于String字符串笔试面试重点

Java之关于String字符串笔试面试重点

Java之关于String字符串笔试面试重点

目录

一.关于字符串常量

1.关于字符串产生的三种方式

2.关于字符串的常量池

3.直接赋值法和new的方式产生对象的区别

二.关于intern方法

1.情况一(已经包含)

2.情况二(已经包含)

 3.情况三(未包含)

 4.情况四

三.关于字符串的不可变性

1.了解字符串的不可变性

2.String对象不可变性的原因

3.相关的考题


一.关于字符串的常量池

1.关于字符串产生的三种方式

String s1="abc";

String s2=new String("abc");

char[] value={'a','b','c'};

String s3=new String(value);

2.关于字符串的常量池

当字符串采用直接赋值法的时候,JVM会维护一个字符串的常量池.

当字符串常量第一次产生的时候,就会产生字符常量,放入到常量池中

当使用直接复制法再次产生相同的对象时,若常量池中存在该值的对象直接复用常量池中的对象,并不会产生新的对象

3.直接赋值法和new的方式产生对象的区别

首先需要明确==比较的引用对象地址是否相同,而不是值!!!

        String s1 = "abc";String s2 = new String("abc");char[] value = {'a', 'b', 'c'};String s3 = new String(value);String s4 = "abc";System.out.println(s1 == s2);//falseSystem.out.println(s1 == s4);//trueSystem.out.println(s2 == s3);//falseSystem.out.println(s3 == s4);//fasle

关于这样四对字符串==的比较,因为s1和s4都采用的是直接赋值法,所以他们对象的产生在常量池中,由于他们的值都是相同的,所以他们指向同一个地址的值.

而new对象的产生是在堆上,所以他们都是指向不同地址的对象,虽然他们的值都是一样的

二.关于intern方法

这是一个手动置入常量池的方法:调用此方法,会将当前字符串对象尝试置入常量池

主要分为两种情况:

1.若常量池中已经包含了当前对象的内容,不会将当前对象置入常量池,返回值是常量池中原有的对象地址
⒉若常量池中没有包含当前字符串对象的内容,就将当前对象置入常量池之中,返回值是当前对象的地址

1.情况一(已经包含)

        String s1 = "abc";String s2=new String("abc");System.out.println(s1==s2);//falses2=s2.intern();System.out.println(s1==s2);//true

第一个s1==s2输出的是false,前边已经讲解过了,因为new对象是在堆上产生的,s1是在常量池中产生,==比较的地址,显然他们的地址不一样.

第二个s1==s2,因为值为"abc"已经存在与常量池中了,不会将s2对象置入到常量池中,但是结果的返回值为s1的地址,此时令s2=s2.intern(),s2的地址便与s1的地址相同

2.情况二(已经包含)

        String s1 = "abc";String s2=new String("abc");System.out.println(s1==s2);//falses2.intern();System.out.println(s1==s2);//false

 第一个s1==s2同上

第二个s1==s2,因为值为"abc"已经存在与常量池中了,不会将s2对象置入到常量池中,所以s2指向的还是s2原本的地址,s1与s2的地址不相同,所以返回的false

 3.情况三(未包含)

        char[] ch = {'a', 'b', 'c'};String s2 = new String(ch);s2.intern();String s1 = "abc";System.out.println(s1 == s2);//true

new出来s2的时候,常量池中并没有"abc"这个字符串,这个时候将s2压入到常量池中,然后s1直接赋值法直接就是和s2压入到常量池的地址一样了,具体看下图

 4.情况四

        String s2 = new String("abc");//"abc"是字符串常量,此时存在于常量池中了s2.intern();//此时常量池中已经存在"abc",因为上边new对象的时候"abc"在常量池String s1 = "abc";System.out.println(s1 == s2);//false

因为刚开始new对象的时候是拿常量池中的"abc"new出来,所以此时常量池中已经有了"abc",这个时候s2的地址还是处在堆中,s1直接赋值"abc"在常量池中,所以s1和s2的地址不一样

三.关于字符串的不可变性

1.了解字符串的不可变性

String对象一旦产生,字符串对象中保存的值不可改变

        String s1="hello";s1+=",world";s1+="!!";System.out.println(s1);

很多人可能会疑问,这样s1的值不是改变了吗?

这样一段代码,改变的是s1的引用,它的指向一直在改变,不断指向新的字符串常量

不断在常量池中产生了新的字符串对象str这个引用一直在变
字符串常量池中一旦字符串对象产生,内容不变的.这就是字符串对象的不可变性

2.String对象不可变性的原因

 String对象的底层是用一个字符串数组进行保存的.

有些人可能以为String对象不可变是因为char数组是final修饰的,实则这是一个很大的误解,因为final修饰的引用对象,只是它的地址值不会发生改变,它的实际内容还是会改变的,下面这段代码便可以很好的证明

        final char[] ch={'a','b','c'};System.out.println(Arrays.toString(ch));//[a, b, c]ch[0]='g';System.out.println(Arrays.toString(ch));//[g, b, c]

实际上是因为字符串数组前边的private进行修饰,因为String类中没有具体的get和set方法,所以我们在外边的时候,无法直接对char数组进行改变

所以我们常用的subString,replace等操作字符串的方法,并没有对原来的字符串进行了改变,只是产生了新的字符串对象

        String s="abcdefg";String substring = s.substring(0, 5);System.out.println(s);//abcdefg

3.相关的考题

    public static void main(String args[]){String str = new String("good");char[ ] ch = { 'a' , 'b' , 'c' };change(str,ch);System.out.println(str);System.out.println(ch);}public static void change(String str,char ch[ ]){str = "abc";ch[0] = 'g';}

对于这样一段代码的输出是什么?

我们学习过了字符串的不可变性,进入到change方法之后,字符数组直接在堆进行改变,而对字符串的改变,直接产生了新的字符串,str指向了新的地址,而主方法里的str指向的还是原来的地址,所以最后输出

str="good"
ch="gbc"