字符串(超详细)

字符串

一:String概述

Java.lang.String类代表字符串,Java程序中的所有字符串文字(例如"abc")都为此类的对象

二:String的注意点

字符串的内容是不会发生改变的,它的对象在创建后不能被更改。

例如:

String name = "尼古拉斯阿玮";
String schoolName = "黑马程序员";
System.out.println(name + schoolName); // 字符串拼接产生一个新的字符串,对原来的“尼古拉斯阿玮“和“黑马程序”员是没有影响的

在上面这个过程中,一共产生了多少个字符串呢?

三个。

如果字符串这样去写,不是就改变了吗?

String name = "尼古拉斯阿玮";
name = "黑马程序员";

这种情况并不是改变了原来字符串的内容,而是创建了一个新的字符串,把新的字符串再赋值给了前面的变量name,此时并没有改变第一个字符串尼古拉斯阿玮里面的内容。所以在这个过程中,一共产生了两个字符串。

三:总结

(1)String是Java定义好的一个类。定义在java.lang包中,所以使用的时候不需要导包。

(2)Java程序中的所有字符串文字(例如"abcgasfa"),都被视为此类的对象。

(3)字符串不可变,他们的值在创建后不能被更改。

四:创建String对象的两种方式

(1)直接赋值:String name = “尼古拉斯阿玮”;

(2)new 关键字

构造方法 说明

public String() 创建空白字符串,不含任何内容

public String(String original) 根据传入的字符串,创建字符串对象

public String (char[] chs) 根据字符数组,创建字符串对象

场景:要修改字符串的内容

public String(byte[] chs) 根据字节数组,创建字符串对象

场景:以后再网络中传输的数据其实都是字节信息,我们一般把字节信息进行转化,转成字符串,此时就要用到这和构造了。

五:Java的内存模型

目前涉及到的内存会有三个:栈、堆内存、方法区。栈跟方法有关,当方法要运行的时候要进栈,方法里面所有的代码全都执行完了,就要出栈。堆跟对象有关,如果代码中出现了new关键字,只要是new出来的,都是在堆内存当中。方法区就是当代码要运行了,那么字节码文件也是那个class文件,它会加载到方法区当中临时存储。比如现在有一段话:

public class StringDemo{
   
    psvm{
   
        sout("HelloWorld");
    }
}

当代码要运行的时候,他首先要编译成StringDemo.class字节码文件,然后他会把这个字节码文件加载到方法区临时存储。

还有一个区域:StringTable(串池),可以理解为字符串常量池,顾名思义就是用来存字符串的,但是只有直接赋值的方式获取的字符串才存在这个串池当中,如果你是通过new关键字获取的字符串对象,就不在这里面了。在JDK7以前,这个池子是在方法区里面的,但是从JDK7开始,StringTable串池就从方法区挪到了堆内存当中,但是不管他在哪,它的运行机制是不会发生变化的。

假设现在有这样一段代码:

public class StirngDemo {
   
    public static void main(Stirng[] args) {
   
        String s1 = "abc"; // 第一行
        String s2 = "abc"; // 第二行
    }
}

这两种都是直接赋值的,在内存里面是怎么一回事呢?

首先程序启动,main方法加载到栈内存当中,然后从上往下执行每一行代码。第一行代码是直接赋值的,所以这个时候,在main方法里面,首先会创建一个变量s1, =的右边系统就是会去观察串池,会看串池里面有没有abc,现在是第一次没有,就会创建一个新的abc,然后把他的地址值0x0011赋值给s1。执行第二行代码的时候,首先在等号的左边创建一个变量叫做s2,然后等号的右边也是直接赋值的,注意:只要是直接赋值的,他就会去观察串池里面有没有abc,现在已经有了,此时就不会创建一个新的abc了,而是会复用已经存在的abc,所以也会把地址0x0011赋值给s2。

小结:当使用双引号直接赋值的时候,系统会检查字符串在串池当中是否存在,如果不存在,他才会创建一个新的,但是如果已经存在了,就会直接复用。所以以后如果我们想获取一个字符串,更多的是用这种直接赋值的方式,首先代码简单,第二还会节约内存。

手动new出来的:

假设现在有这样一段代码:

public class Test {
   
    public static void main(String[] args) {
   
        char[] chars = {
   'a', 'b', 'c'}; // 第一行
        String s1 = new String(chars); // 第二行
        String s2 = new String(chars); // 第三行
    }
}

首先也是main方法进栈,先执行方法里面的第一行,此时在内存当中就是有一个char类型的数组,数组的地址值假设0x0011,再把地址值0x0011赋值给变量chars,在数组里面存的就是’a’, ‘b’, 'c’这样的三个字符。然后第二行:等号的右边是new出来的,只要是new出来的,那就是在堆里面开辟了一个新的空间。首先等号的左边是变量s1,所以说是在栈里面,等号的右边有new关键字,所以在堆里面就创建了一个小空间,这个空间里面的内容就是字符数组的内容abc,然后再把它的地址值0x0022赋值给s1,s1通过0x0022就能找到我们创建出来的字符串了。第三行:就是把第二行的过程再重复了一遍,这时候会把新的地址值0x0033赋值给s2。这时候s1和s2记录的地址值是不一样的,所以这种方式创建的字符串对象他不会复用,如果相同的字符串比较多,他会浪费内存空间。

六:字符串的常用方法(比较)

==号比较的到底是什么?

基本数据类型:比较的是具体的值。例如:

int a = 10;
int b = 20;
System.out.println(a == b); // false

引用数据类型:比较的是地址值,例如:

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

每一次new出来的时候都是一个新的小空间,所以这里两个new,在堆内存当中肯定有两个小空间,这两个地址值肯定不一样。

如果是下面这种情况:

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

因为这里的s1和s2是直接赋值的,所以复用的是串池里面的,所以地址值是相同的,所以为true。

而下面这种情况:

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

这种情况,s1是new出来的,所以在堆内存中开辟了一个空间,s2是直接赋值的,所以是串池里面的。一个记录堆里面的地址,一个记录串池里面的地址,两个地方都不一样,所以结果肯定是false。

如果想比较内容怎么办?

(1)boolean equals方法(要比较的字符串) 完全一样结果才是true,否则为false

(2)boolean equalsIgnoreCase(要比较的字符串) 忽略大小写比较

public class Test1 {
   
    public static void main(String[] args) {
   
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个字符串");
        String str1 = sc.next(); // new出来的
        String str2 = "abc"
  • 40
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值