当前位置:   article > 正文

Java基础面经——字符串相关_java 为什么substring不等于字符串

java 为什么substring不等于字符串

Java中的字符串就是Unicode字符序列。Java中没有内置的字符串类型,每个用双引号括起来的字符串都是Java中String类的一个实例。

子串

String类中提供了substring()方法来从一个字符串中截取出一部分返回一个小的子串。

String str = "hello";
String s = str.substring(0,3);
System.out.println(s);
输出
hel
  • 1
  • 2
  • 3
  • 4
  • 5

substring方法是包含头不包含尾的一个半开的区间。

字符串拼接

Java中允许使用+号对字符串进行拼接。如果一方为字符串一方不为字符串,则会将其转化为字符串然后拼接。如果与字符串拼接的是一个对象,则会调用其toString方法后进行拼接。

System.out.println("12" + 23);
System.out.println("12" + 2.5);
System.out.println("12" + true);
System.out.println("12" + 'a');
System.out.println("12" + new Person());
System.out.println("12" + new StringBuilder("aaa"));

输出
1223
122.5
12true
12a
12Person@73f792cf
12aaa
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

可以看到字符串与基本数据类型相加,会转换成相应的字符串后相加。与引用类型的数据相加时,会调用引用类型的类的toString方法后再与字符串相加。

System.out.println(1+2+"12");
输出
312
  • 1
  • 2
  • 3

需要注意的是,基本类型如果前面有计算,则会先按照基本类型的计算规则计算,只有到与字符串相加的时候,才会转化为字符串。
如果需要把多个字符串用一个特定的分割符分隔开而形成一个字符串,可以使用静态join方法:

String str = String.join("/", "A", "B", "C");
System.out.println(str);
输出
A/B/C
  • 1
  • 2
  • 3
  • 4

该方法可传递多个参数,第一个参数是分割符,后面可以传入任意个字符序列,参数类型为可变参数类型。
在Java11中,还提供了一个repeat方法,用于重复字符串:

String str = "abc".repeat(3);
System.out.println(str);
输出
abcabcabc
  • 1
  • 2
  • 3
  • 4

该方法接收一个int型参数,表示重复次数,返回为一个字符串。
Java8在做字符串拼接的时候使用的是StringBuilder进行拼接的,但是我使用jdk17进行编译和在IDE中进行反编译并未看到StringBuilder的身影。但是使用+号进行字符串的拼接必然会导致运行速率低下。

不可变字符串

Java中的字符串类String类是被final修饰的,一旦初始化之后就不能改变。Java中没有提供更改字符串中某个字符的方法,拼接之后返回的字符串也不是原来的对象,而是一个新的对象。
相比C语言来说,可能创建一个新的字符串会比直接更改某一个字符来的麻烦,但是不可变字符串却有一个有点:编译器可以让字符串共享。
字符串存储在一个公共的存储池中(字符串常量池),如果需要复制,则复制的和原来的共享相同的字符。

字符串比较

字符串比较使用equals方法,比较两个字符串的内容是否相等。
字符串比较不能使用==号进行比较,该符号只是比较两个字符串的存储位置是否是同一个位置。
如果虚拟机始终将相同的字符串共享,则可以使用==号进行比较,但是实际上并不是这样,实际中,只有字面量是共享的,而+和substring等得到的并不共享。

空串和null值

空串和null值概念不一样,空串指的是初始化后的字符串,只不过字符串的长度为零。null值指的是字符串没有初始化,没有指向的内存区域。

码点和代码单元

这得从Unicode说起,Unicode最初设计只占用16位,代表65535个字符。随着中、日、韩的表意文字加入,很快超出了这个值,现在16位的char值已经不能够满足Unicode字符的需要了。从Java5开始解决这个问题。码点是指一个编码表中的某个字符对应的代码值。在Unicode标准中,码点采用十六进制书写,并加上前缀U+。Unicode的码点可以分为17个代码平面。第一个代码平面基于多语言平面,包括码点从U+0000到U+FFFF的“经典”Unicode代码。其余的16个平面的码点从U+10000到U+10FFFF,包括辅助字符。
Java字符串由Char值序列组成,采用UTF-16编码表示Unicode码点的代码单元。对于常用的Unicode字符,只需要一个代码单元就可以表示,而辅助字符则需要一堆代码单元表示。
当使用辅助字符时,char返回的只是辅助字符两个代码单元中的一个,如果应用中可能会出现U+FFFF以上字符,则不要使用char。同时也推荐直接不要使用char类型,这太底层了。
虚拟机不一定把字符串实现为代码单元序列。在Java9中,只包含单字节代码单元的字符串使用byte数组实现,所有其他字符串使用char数组。

字符串创建了几个对象

1、字面量创建对象

String str = "abc";
  • 1

对于字面量,分为两种情况。
情况一:如果该字面量在常量池中未存在,会在常量池中创建该字符串的对象,并将其地址赋值给变量。变量存储的是常量池中对象的地址,创建了一个对象。
情况二:如果该字面量在常量池中存在,则直接将常量池中的对象地址赋值给变量。变量存储的是常量池中对象的地址,没有创建对象。
2、使用new创建对象

String str = new String("abc")
  • 1

对于使用new创建的字符串,也可分为两种情况。
情况一:常量池中未存在该字符串,首先在常量池中创建一个对象,然后将常量池中的对象拷贝到堆内存中一份,并将堆内存中对象的地址赋值给变量。变量存储的是堆内存中对象的地址,该情况下创建了两个对象,一个在常量池中,一个在堆内存中。
情况二:常量池中存在该字符串,直接将常量池中的对象拷贝到堆内存中,并将堆内存中对象的地址赋值给变量。变量存储的是堆内存中对象的地址,该情况下只创建了一个对象。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/617960
推荐阅读
相关标签
  

闽ICP备14008679号