Java String类内存分配

1. 创建字符串

//1. 直接赋值
String str1 = "Hello world";
//2. new对象
String str2 = new String("Hello World");
//3. 根据字符数组内容构造
char[] array = {'a','b','c'};
String str3 = new String(array);

2. 字符串比较

2.1 equals()

==是用来比较地址的,想要比较两个字符串内容是否相等,要使用函数equals();

String str1 = "Hello";
Stirng str2 = "hello";
System.out.println(str1.equals(str2)); //法1.false
System.out.println(str2.equals(str1)); //法2.false

注意事项:

  1. 比较函数equals()是区分大小写的比较;
  2. 当比较两者不为null时,上述两种写法均可;但如果str1 = null,null值引用方法会报错,所以使用方法2更安全。

2.2 equalsIgnoreCase()

与equals()方法类似,是不分区大小写的比较方法。

2.3 compareTo()

int compareTo(String anotherString):按字典顺序比较两个字符串

返回值为int,从第一个字符开始比较两个字符串,

如果不相等,返回两者的ASCII差值;

如果相等就比较第二个,以此类推,直到不等为止,或str1与str2长度不同,但对应位字符相同,此时返回长度差。

public static void main(String[] args) {
        String str1 = "Stringa";
        String str2 = "Stringc";
        String str3 = "Stringa1234";

        int result1 = str1.compareTo(str2);
        System.out.println(result1); //-2
			  int result2 = str1.compareTo(str3);
        System.out.println(result2); //-3
    }

2. 字符串常量池

2.1 共享设计模式

String类的设计使用了共享设计模式,在JVM底层实际上会自动维护一个对象池(字符串常量池)。

a)直接赋值法

  • 若采用直接赋值法创建字符串,将该实例化对象,即字符串内容保存在字符串常量池中。例如str1。
  • 若下次使用直接赋值法创建字符串,在字符串常量池中已有指定内容,那么直接进行引用,无需再开辟新的空间。

b)构造方法

  • 若采用String构造方法会在堆内存中开辟出两块内存空间,其中一块会成为垃圾空间。
  • 只要是构造方法new出来的对象都是要再堆中开辟空间的,所以会出现同一字符串可能被存储多次,浪费时间。例如str2。

c) 拼接字符串

  • 若拼接两者均字符串常量,那么拼接后的字符串与源字符串变量视为相同变量,公用一个内存地址。例如str3。
  • 只要有其一为变量或是new出来的字符串,那么拼接时会new新的字符串存在堆上。例如str6、str7。

2.2 内存结构分析

String str1 = "Hello";
String str2 = new String("Hello"); //编译的时候这个地方就相当于String str3 = "hello"
String str3 = "He"+"llo";

String str4 = "He";
String str5 = "llo";
String str6 = str4 + str5; 

String str7 = "He"+ new String("llo");

System.out.println(str1 == str2);  //false
System.out.println(str1 == str3);  //true
System.out.println(str1 == str6);  //false
System.out.println(str1 == str7);  //false

在这里插入图片描述

面试题:请解释String类中两种对象实例化的区别?

A:
直接赋值法:只会开辟一块堆内存,并且该字符串对象可以自动保存再字符串常量池中以供下次使用。
构造方法:会在堆内存中开辟出两块内存空间,且一块作为垃圾空间,不会自动保存再字符串常量池中,可以手动入池。

2.3 手动入池

在使用构造函数创建字符串时,字符串内容不会自动保存再字符串常量池中,所以可以采用intern()方法手动入池。

String str1 = "Hello"; //str1存放在字符串常量池中
String str2 = new String("Hello").intern(); //str2手动入池
System.out.println(str1 == str2);  //true

3. 字符串与字符转换

  • 获取指定位置字符 charAt()
String str = "hello world";
System.out.println(str.charAt(0)); //获取下标为0的字符
  • 字符串转字符数组 toCharArray()
String str = "hello wordl";
char[] array = str.toCharArray();
  • 字符数组转字符串
char[] array = {'a','b','c'};
String str1 = new String(array); //全部转换
String str2 = new String(array,0,1); //部分转换

4. 字符串不可变

字符串是一种不可变对象,它的内容不可改变。

例如下述代码,修改前str1和str2都指向同一块内存地址,但是修改后,str1指向"world"所在的新地址,而str2还指向原来的“hello”的地址,所以不再指向同一个地址。由此可见,字符串修改,本质上是是该引用指向了新的对象,而不是对原对象的修改。

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = str1;
        System.out.println(str1); //hello
        System.out.println(str2); //hello
        System.out.println(str1 == str2); //true
        System.out.println("============");
        str1 = "world";
        System.out.println(str1); //world
        System.out.println(str2); //hello
        System.out.println(str1 == str2); //false
    }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值