吊锤面试官的String知识大全

一、基本特征

String:字符串,使用一对""引起来表示。
1.String声明为final的,不可被继承
2.String实现了①Serializable接口:表示字符串是支持序列化的。
②实现了Comparable接口:表示String可以比较大小
3.String内部定义了final char[] value用于存储字符串数据
4.String:代表不可变的字符序列。简称:不可变性。

  • 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
  • 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
  • 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串的。

    @Test
    public void test1(){
    
    
        String s1 = "abc";//字面量的定义方式
        String s2 = "abc";
        s1 = "hello";
        
        
        System.out.println(s1 == s2);

        System.out.println(s1);//hello
        System.out.println(s2);//abc

        System.out.println("*****************");

        String s3 = "abc";
        s3 += "def";
        System.out.println(s3);//abcdef
        System.out.println(s2);

        System.out.println("*****************");

        String s4 = "abc";
        String s5 = s4.replace('a', 'm');
        System.out.println(s4);//abc
        System.out.println(s5);//mbc

    }

1 测试方法的前两行执行后s1和s2都指向了存储abc的字符串常量池空间,此时s1= =s2是true ( 对象引用间的 == 是判断两个引用指向的存储空间是否一致)
2 执行完第三行s1指向的存储abc的空间,s2指向了存储hello的空间,s2与存储abc的空间没有关系了,此时s1==s2是false
3 s3和s4分析同上,改的话就一定会改变引用的指向,改变后的引用与原先的存储空间失去关系
在这里插入图片描述

二、String对象的创建

1 String的实例化方式:
方式一:通过字面量定义的方式
方式二:通过new + 构造器的方式
2 String str = “abc” 和 String str2 = new String(“abc”)的区别
字符串常量是存储在字符串常量池中(存储abc的常量池地址加上是0x4399),而字符串对象正如其它对象一样存储在堆中,只不过str2所指向的堆中存储的是常量池中abc的存储空间,即value=0x4399,
总之:构造器赋值的方法是在堆空间开辟一块存储引用值的空间(0x4399),同时,如果字符串常量池没有abc就先创建再指向,有abc就直接指向即可
在这里插入图片描述
3 更多案例

    @Test
    public void test2(){
    
    
        //通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
        String s1 = "javaEE";
        String s2 = "javaEE";
        //通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
        String s3 = new String("javaEE");
        String s4 = new String("javaEE");

        //不理解的看下面的图解1
        System.out.println(s1 == s2);//true
        System.out.println(s1 == s3);//false
        System.out.println(s1 == s4);//false
        System.out.println(s3 == s4);//false

        System.out.println("***********************");
        Person p1 = new Person("Tom",12);
        Person p2 = new Person("Tom",12);
        
        //不理解过程的看下面的图解2,String重写的equals是方法不考虑存储空间只考虑值是否相等的函数,下面会具体讲解
        //这里无论是p1.name还是p2.name都不需要考虑堆的问题,而字符串常量池相同的内容只会占一份空间
        System.out.println(p1.name.equals(p2.name));//true
        System.out.println(p1.name == p2.name);//true

        p1.name = "Jerry";
        System.out.println(p2.name);//Tom
    }

在这里插入图片描述
在这里插入图片描述

三、String的不同拼接操作

    /*
1 常量与常量的拼接还是在常量池中
2 常量与变量的拼接结构在堆中
3 变量与变量的拼接结果也在堆中
4 如果拼接的结果调用intern那么返回值就在常量池中
5 注意:变量不单单是指字符型变量,其他类型变量与字符串拼接的结果也是在堆中
*/
    @Test
    public void test5(){
    
    
        String s1 = "hello";
        String s2 = "world";

        String s3 = "helloworld";
        String s4 = "hello" + s2;
        String s5 = s1 + "world";
        // s5本来在在堆中,s5调用intern()后对s5自己没有影响,
        // 但得到的s6的值是“helloword”且存储在字符串常量池中,验证如下
        String s6 = s5.intern();
        System.out.println(s3 == s6);//true

        String s7 = s1 + s2;
        String s8 = "hello" + "world";

        System.out.println(s3 == s4);//false
        System.out.println(s3 == s5);//false
        System.out.println(s3 == s8);//true
        System.out.println(s3 == s7);//false
        System.out.println(s5 == s8);//false
        System.out.println(s5 == s7);//false
        System.out.println(s8 == s7);//false

        Integer a = 123;
        String s9 = a + "";
        String str = "123";
        System.out.println(str == s9); //false
    }

部分字符对象图解
在这里插入图片描述

四、常见字符串方法

看我的另一篇博客:String相关方法大全

五、String与基本数据类型的转换

1 String 与基本数据类型、包装类之间的转换。
String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型
包装类 --> String:调用String重载的valueOf(xxx)

 @Test
    public void test5(){
    
    
        String str1 = "123";
        //int num = (int)str1;//错误的
        int num = Integer.parseInt(str1);

        String str2 = String.valueOf(num);//"123"
        String str3 = num + "";
        System.out.println(str3);
        //源码过程是: valueOf => 调用Interger.toString(),返回的是new String(xxx);
        //也就是str2指向的堆,str1指向的是方法区的字符常量区
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
    }

2 String 与 char[]之间的转换
String --> char[]:调用String的toCharArray()
char[] --> String:调用String的构造器

扫描二维码关注公众号,回复: 12474154 查看本文章
@Test
    public void test2(){
    
    
        String str1 = "abc123";  //题目: a21cb3

        char[] charArray = str1.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
    
    
            System.out.println(charArray[i]);
        }

        char[] arr = new char[]{
    
    'h','e','l','l','o'};
        String str2 = new String(arr);
        System.out.println(str2);
    }

3 String 与 byte[]之间的转换
编码:String --> byte[]:调用String的getBytes()
解码:byte[] --> String:调用String的构造器

编码:字符串 -->字节 (看得懂 —>看不懂的二进制数据)
解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 —> 看得懂)

说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。

@Test
    public void test3() throws UnsupportedEncodingException {
    
    
        String str1 = "abc123中国";
        byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码。
        System.out.println(Arrays.toString(bytes));

        byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码。
        System.out.println(Arrays.toString(gbks));

        System.out.println("******************");

        String str2 = new String(bytes);//使用默认的字符集,进行解码。
        System.out.println(str2);

        String str3 = new String(gbks);
        System.out.println(str3);//出现乱码。原因:编码集和解码集不一致!


        String str4 = new String(gbks, "gbk");
        System.out.println(str4);//没有出现乱码。原因:编码集和解码集一致!


    }

面试题补充:

1、String str2 = new String(“abc”)涉及几个对象
答:涉及到了两个,一个是很显眼的str2,另一个是String底层创建的char[]型字符数据,这个数据有三个元素,a、b、c,对应的就是字符串常量池的内容

2 看代码

public class StringTest {
    
    
    String str = new String("good");
    char[] chars = {
    
    'a','b','c','d'};

    public void change(String str,char[] chs){
    
    
        str = "test";
        chs[0] = 'b';
    }
    @Test
    public void test1(){
    
    
        StringTest st = new StringTest();
        st.change(st.str,st.chars);
        System.out.println(st.str);
        System.out.println(st.chars);
    }

}

结果为
在这里插入图片描述
解题的关键是:参数引用str和属性引用st.str不是同一个对象,参数对象str的改变不代表属性引用st.str的变化,最终结果图解如下
在这里插入图片描述

需要注意的是,str一开始也是指向的good存储区

3 看代码

@Test
    public void test4(){
    
    
        String s1 = "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2 + "hadoop";
        System.out.println(s1 == s3);//false

        final String s4 = "javaEE";、
        String s5 = s4 + "hadoop";
        System.out.println(s1 == s5);//true

    }

原因是,①字符串常量拼接字符串常量结果在方字符串常量池中
②s4是被final修饰的String类型的变量,相当于一个常量

猜你喜欢

转载自blog.csdn.net/wwwwwww31311/article/details/113482513
今日推荐