常用方法
这些用法应该烂熟于心
String string = "Hello World!";
String string2 = new String("abc");
//1.获取字符串长度
string.length();
//2.截取一个字符
string.charAt(0);
//3.替代getChars()的一种方法是将字符存储在字节数组中,该方法即getBytes()
byte[] bytes = string.getBytes();
//4.转换成字符数组
char[] chars = string.toCharArray();
//5.判断字符串开始和结束
boolean h = string.startsWith("H");
boolean b = string.endsWith("World!");
//6.indexOf() 查找字符或者子串第一次出现的地方。
int e = string.indexOf('e');
//7.lastIndexOf() 查找字符或者子串是后一次出现的地方
int o = string.lastIndexOf('o');
//8.截取字符串
String substring = string.substring(1);//指定位置到结束
String substring1 = string.substring(1, 3);//指定位置到指定位置,结果"el"
//9.替换(这个替换是全部的)。
String replace = string.replace('o', 'z');
//10.连接两个字符串
String concat = string.concat(string2);
//11.去掉起始和结尾的空格
String trim = string.trim();
//12.将基础数据类型转换为字符串类型
String s = String.valueOf(333);
//13.大小写转换
string.toLowerCase();
string.toUpperCase();
从源码去理解
定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
从上面的定义我们可以看出
- Final 标识不允许集成重载. jdk中还多重要类都是final 标识, 防止应用程序继承重载以影响jdk的安全
- 继承Serializable 接口, 可以放心的序列化
- Comparable 接口, 可以根据自然序排序.
- CharSequence 字符串的重要接口
- char数组 value . Final 修饰.
- hash字段 int, 表示当前的hashCode值, 避免每次重复计算hash值
字符串构造方法3+1
- String string = "abcd";
- public String()创建的是一个空字符
- public String(char[])穿进去一个字符数组
- public String(byte[])传递进去一个字节数组
注意 直接使用双引号的形式,创建色字符串是保存在字符串常量池当中的
new 关键字创建的方法,则是创建一条引用,然后指向了一个字符数组。
空白构造方法其实是生成 "" 字符串传入其他字符串的构造方式其实只是把其他字符串的value 和hash 值的引用复制一份, 不用担心两个字符串的value和hash 互相干扰. 因为String类中没有修改这两个值的方法, 并且这两个值是private final修饰的, 已经无法修改了。
空白构造方法中没有设置hash的值, 则使用 hash的默认值 // Default to 0
hashCode方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
- 重写了hashcode 方法,可以看出hashcode 和每个字符都有关
字符串的拼接concat方法和join静态方法
- concat方法
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
直接在内存中复制一份新的数组, 在new 一个String对象. 线程安全. 性能较低.
也可以直接是用 + 拼接.
- join静态方法
内部发现还是使用StringBuilder来实现, join 完全就是一个为了使用方便的一个工具方法。
trim 方法
从前后遍历空白字符, 判断空白字符是使用的 char <=' ' 来判断的, 后面在使用substring来截取非空白字符
substring方法
内部使用public String(char value[], int offset, int count) 构造方法来生成新的字符串, 在这个构造方法内部会有数组的赋值
valueOf方法
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
// 内部使用传入对象的自己的toString方法, 传入对象如果没有重载toString方法, 就使用默认的toString方法.
public static String valueOf(char data[]) {
return new String(data);
}
// 根据传入的数组来选择合适的构造方法来生成String对象
public static String valueOf(boolean b) {
return b ? "true" : "false";
}
// 根据传入布尔值
static copyValueOf方法
public static String copyValueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
// 静态工具方法, 默认使用合适构造方法来截取和生成新新的字符串
了解了这些应该再去看看密切相关的两个东西StringBuffer、StringBuilder
- 如果要操作少量的数据用 String
- 单线程操作字符串缓冲区 下操作大量数据 StringBuilder
- 多线程操作字符串缓冲区 下操作大量数据 StringBuffer
注意
每次执行“+”操作时jvm都要new一个StringBuffer对象来处理字符串的连接,这在涉及很多的字符串连接操作时开销会很大。
这一小节原文链接:https://blog.csdn.net/longfulong/article/details/78700239
1.StringBuffer()的初始容量可以容纳16个字符,当该对象的实体存放的字符的长度大于16时,实体容量就自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。
2.StringBuffer(int size)可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符序列的长度大于size个字符时,实体的容量就自动的增加。以便存放所增加的字符。
3.StringBuffer(String s)可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动的增加,以便存放所增加的字符。
扩容算法:
使用append()方法在字符串后面追加东西的时候,如果长度超过了该字符串存储空间大小了就需要进行扩容:构建新的存储空间更大的字符串,将久的复制过去;
再进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容
尝试将新容量扩为大小变成2倍+2 if 判断一下 容量如果不够,直接扩充到需要的容量大小。
网友评论