Java基本字符串操作——
细绳
什么是字符串? 如果从字面上理解的话,就是由多个字符连接在一起组成的字符序列。 为了更好的理解上面的理论,我们先来解释一下字符序列。 字符顺序:将多个字符按照一定的顺序排列; 并且字符序列作为字符串的内容而存在。 因此,字符串可以理解为多个字符按一定顺序排列的组合。
如果还是很难理解,没关系,我还有法宝。 我们可以用烤肉串来比喻。 我们可以把字符串想象成烤肉串,烤肉串上的每一块肉就相当于一个字符。 把一块块肉按照肥瘦的顺序排列串起来,就成了我们吃的烤肉串。 同样,将多个字符按照一定的顺序串起来就形成一个字符串。
字符串的分类,字符串分为两种:可变字符串和不可变字符串; 这里的不可变和可变是指字符串的对象是否相同。 是因为对象的内容吗? 根据更改创建新对象。
种类
该类表示一个不可变的字符串。 当前类对象创建后,该对象的内容(字符序列)保持不变,因为一旦内容发生变化,就会创建一个新的对象。
对象创建:
方法一:通过字面赋值创建,s1 = "laofu"; 请注意,这里是双引号:“”,与字符char类型的单引号:''不同; 方法二:通过构造函数创建,s2 = new("laofu"); ;
以上两种方式创建的对象在JVM中是如何分布的呢? 有什么区别?
方法1和方法2在JVM中是如何分布的?
字符串对象在JVM中的分布
上图中的常量池:用于存储常量的本地内存区域,位于方法区。 常量池分为编译常量池和运行常量池两种:
方法一和方法二有什么区别?
方法一:s1 = "老福"; 可以只创建一个对象,也可以不创建任何对象; 如果常量池中已经存在“laofu”,则直接引用对象s1,不会创建新对象; 否则,会先在常量池中创建常量“laofu”的内存空间,然后再引用。
方法二:s2 = new("老福"); 最多会创建两个对象,最少会创建一个对象。 可以使用new关键字创建一个对象,该对象会在堆空间中创建一块内存区域。 这是第一个对象; 那么该对象中的字符串文字可以创建第二个对象,第二个对象如方法一所述。 ,有可能不会被创建,所以至少创建一个对象。
字符串的本质,字符串其实底层就是char[],char代表一个字符,比如:
String str = "laofu";
// 等价于
char[] cs = new char[]{'l','a','o','f','u'};
字符串实际上是底层的 char[]。
对象的空值:
对象引用为空,即:s1 = null; 此时s1还没有初始化,JVM中还没有分配内存空间。 对象内容为空字符串,例如:s2 = ""; 此时对象s2已经初始化完毕,值为“”,JVM已经为其分配了内存空间。
字符串比较:使用“==”和“”会有不同的效果。 详细内容在之前的文章中已经分享过:
使用“==”符号:用于比较对象引用的内存地址是否相同。 用法:与类中的“==”符号相同,但在自定义类中,建议重写该方法来实现比较自身内容的细节; 由于类重写已经覆盖了该方法,因此它会比较字符内容。
该方法的实现细节
所以你可以检查字符串是否不为空,如下所示:
对象引用不能为 null: s1 != null;; 字符内容不能为空字符串(""): "".(s1);;
如果满足以上两个条件,就说明该字符串确实为空!
字符串拼接:Java中的字符串可以使用“+”进行拼接,那么代码中的字符串拼接在JVM中是如何处理的呢? 我们举个例子来说明一下:对比一下字符串拼接代码编译前后的代码,看看JVM是如何处理字符串拼接的。
字符串连接的JVM实现
从上面的例子中不难发现,JVM会对字符串拼接做一些优化操作。 如果字符串文字被拼接,那么无论有多少个字符串,JVM都会进行相同的处理; 如果是对象之间的拼接,或者对象与文字之间的拼接,或者参与拼接的方法执行结果,会在内部使用先获取对象的值,然后使用方法进行拼接。 由此可以得出结论:
使用字符串文字创建的字符串,即单独使用“”引号创建的字符串,是直接量,在编译时会存储在常量池中; 使用new("")创建的对象将被存储到堆内存中,并在运行时创建; 使用仅包含直接量的字符串连接运算符,例如:“aa”+“bb”创建直接量。 这样的字符串可以在编译时确定,因此它也会存储在常量池中; 使用包含直接量的字符串表达式(如:“aa”+s1)创建的对象是在运行时创建的,并且该对象存储在堆中,因为底层是创新的对象来实现拼接。 的;
5、无论是使用变量还是调用方法来连接字符串,变量的值和方法的返回值都只能在运行时确定,并且不存在编译优化操作。
常用API
以下是一些常用的 API。 更多信息可以查阅jdk手册。 做Java的时候一定要学会查阅jdk手册。
jdk手册
创建和转换:
// 把字符串转换为byte数组。
byte[] getBytes();
// 把字符串转换为char数组。
char[] toCharArray();
// 把byte数组转换为字符串。
String(byte[] bytes);
// 把char数组转换为字符串。
String(char[] value);
获取字符串信息
// 返回此字符串的长度。
int length();
// 返回指定索引处的 char 值。
char charAt(int index);
// 返回指定字符串在此字符串中首次(从最左边算起)出现处的索引。
int indexOf(String str);
// 返回指定字符串在此字符串中最后(最右边算起)出现处的索引。
int lastIndexOf(String str);
字符串比较判断
// 将此字符串与指定的对象比较。
boolean equals(Object anObject);
// 将此 String 与另一个 String 做忽略大小写的比较。
boolean equalsIgnoreCase(String anotherString);
// 将此字符串与指定的 CharSequence 比较,比较的是内容;
// ps:String类是现实了CharSequence(字符序列)接口的。
boolean contentEquals(CharSequence cs);
字符串大小写转换:调用该方法的字符串为当前字符串
// 把当前字符串转换为大写
String toUpperCase();
// 把当前字符串转换为小写
String toLowerCase();
/
首先使用//分别拼接字符串30000次,比较各自的损耗时间。 经过测试,我们发现:
因此,开发时拼接字符串时,优先使用/,不要轻易使用。
和区别
和 都代表变量字符串,其功能方法是相同的。 但唯一的区别是:
由于其性能较高,建议在对并发安全性要求不高的情况下使用。 这样的情况还会有很多。 使用无参数构造函数,在底层创建了一个长度为 16 的 char 数组:
无参构造函数
此时数组只能存储16个字符。 如果超过16个字符,则会自动扩展(创建一个长度更大的数组,然后将之前的数组复制到新数组中)。 此时性能极低; 如果你事先知道大约需要存储多少个字符? 可以通过构造函数设置字符的初始值:
设置初始值的构造函数
// 创建一个长度为80的char数组.
new StringBuilder(80);
常用方法:
// 追加任意类型数据到当前StringBuilder对象中。
append(Object val);
// 删除字符串中指定位置的字符。
StringBuilder deleteCharAt(int index);
end.虽然我不认真,但我才华横溢