java基础-字符串
前言
在开发中,字符串String类型是我们使用很频繁的对象了(注意它不是基本数据类型)。知道如何创建字符串、常用的方法、相关类的使用、字符串常量池等是我们技能中必不可少的一部分。比如它能:减少内存消耗、加快程序运行速度、提高我们的开发效率等。
有问题的地方或者遗漏的知识点请大佬及时指正!!
一、String
1.1 从类分析String
- 通过源码,我们可以看到String被final修饰,说明这个类
不能被继承
;而对应的value也被final修饰,值是不可变
的,每次操作都会是新的String对象,然后将指针指向新的String对象。 - 我们也应该注意:
String不属于基本类型
。8种基本数据类型:byte、short、int、long、float、double、char、boolean,而String属于对象。
1.2 String 常用方法
1.2.1 intern()
public native String intern();
- 这个方法会将创建的字符串放入字符串常量池。平时开发中,我们在代码中没有将一些字符串定义字符串常量变量,但是又经常使用某些字符串,为了减少频繁创建对象和内存的消耗,我们可以在对应的字符串后边加上这个方法。
1.2.2 join()
方法源码如下:
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// Number of elements not likely worth Arrays.stream overhead.
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
- delimiter 表示拼接符号,也就是分隔符
- elements 需要拼接的数据
平时我们需要将多个字符串拼接起来,就可以用这个方法。这里有个StringJoiner对象,后边介绍
。
@Test
public void testString(){
//将a b c通过 "," 拼接
System.out.println(String.join(",", new String[]{"a","b","c"}));
}
1.3 String str="i"和String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样,前者Java虚拟机会将其分配到常量池中,后者会被分配都堆内存中
二、StringJoiner
顾名思义,这个类用于字符串连接。prefix表示前缀,delimiter表示分隔符,suffix表示后缀。
2.1 用法
List<String> stringList = new ArrayList<>(3);
stringList.add("a");
stringList.add("b");
stringList.add("c");
//表示用用逗号","分隔,"["作为前缀,用"]"作为后缀
StringJoiner stringJoiner = new StringJoiner(",", "[", "]");
for(String str:stringList){
stringJoiner.add(str);
}
System.out.println(stringJoiner);
System.out.println(stringJoiner.merge(stringJoiner));
输出结果:
2.2 源码分析
1.进入add方法
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
2.进入prepareBuilder
方法
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
我们会发现,StringJoiner底层字符串拼接用了StringBuilder,同时在拼接上 了前缀或者分隔符。
3.进入toString()
@Override
public String toString() {
if (value == null) {
return emptyValue;
} else {
if (suffix.equals("")) {
return value.toString();
} else {
int initialLength = value.length();
String result = value.append(suffix).toString();
// reset value to pre-append initialLength
value.setLength(initialLength);
return result;
}
}
}
重写了toString方法,添加上后缀。
2.3 总结
当出现拼接字符串的用上String.join或者StringJoiner,完美,就不用自己定义一个String 或者StringBuilder慢慢拼接了。
三、StringBuilder和StringBuffer
3.1 StringBuilder
3.1.1 从类分析StringBuilder
通过类的关系我们可以看出:
- StringBuilder被final修饰,这个类不能被继承。
- StringBuilder继承AbstractStringBuilder这个抽象类,底层采用数组,和String的区别就是没有被final修饰,值可变。这里也就是出现大量字符串拼接用其代替String的原因,String 需要不断的生成新的对象,而StringBuilder只需要改变值。
- 默认的情况下,value的大小是16
3.1.2 StringBuilder如何扩容
知道对象底层如何扩容,在新建对象的是否对初始化大小,能够较少内存的消耗(可以让这个对象扩容的合理,减少无用的空间),也可以在在一定程度上加快程序的运行速度(底层数组的长度变了,减少了循环的次数)
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
每次调用append实则调用父类AbstractStringBuilder 的append方法,进入ensureCapacityInternal->expandCapacity
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
void expandCapacity(int minimumCapacity) {
// 将新的大小设置为当前值长度的二倍加上2
int newCapacity = value.length * 2 + 2;
//比较newCapacity 和minimumCapacity(=拼接的长度+原来值的长度)的值,将newCapacity 设置中间一个大的
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
//将原来的值,赋值到新的数组,并赋值给value
value = Arrays.copyOf(value, newCapacity);
}
Arrays.copyOf方法如下:
3.2 StringBuffer
在方法上加了锁,是线程安全的。其他的和StringBuilder类似。
本文地址:https://blog.csdn.net/qq_32748869/article/details/109813465
下一篇: A站遭攻击导致千万用户数据泄露