本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-06-25
import org.junit.Test;
public class StringTest {
/**
* String 字符串 使用双引号表示
* 1、声明为final 不可被继承
* 2、String实现了Serializable接口:表示字符串是支持序列化的
* 3、String实现了Comparable接口,表示String是可以比较大小的
* 4、String内部定义了 final char[] value 执行该字符串的值
* 5、String代表不可变的字符序列,即不可变性
*/
// 不可变性的体现
@Test
public void test1() {
String s1 = "abc"; // 字面量的定义方式
String s2 = "abc";
System.out.println(s1 == s2); // true s1和s2是两个String对象,所以比较的是地址,这里说明两个是同一个地址
s1 = "hello";
System.out.println(s1); // "hello"
System.out.println(s2); // "abc"
// 既然两者全等,为什么修改s1后,s2没有变化
// 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值是声明在字符串常量池中
// 字符串常量池中是不会存储相同内容的字符串的
// 当s1和s2都指向"abc" 就执行字符串常量池中的同一个地址
// 当修改s1之后,会新开辟一个字符串常量"hello"
String s3 = "abc";
System.out.println(s2 == s3); // true
s3 += "def";
System.out.println(s3); // "abcdef"
System.out.println(s2); // "abc"
// s2依然为"abc" 因为当对字符串重新赋值时 需要重写指定内存区域赋值 不能使用原有的进行赋值
String s4 = "abc";
System.out.println(s4 == s2); // true
String s5 = s4.replace('a', 'm');
System.out.println(s4); // "abc"
System.out.println(s5); // "mbc"
// 当调用String的replace方法修改字符串,也需要重新指定内存区域赋值 不能使用原有的进行赋值
}
// String对象的创建
@Test
public void test2() {
String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("abc");
// 使用new的方式创建字符串在内存中其实是创建了两个对象
// 一个是堆空间中的new结构,另一个是final char[] value 对应的常量池中的数据"abc"
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // false
// 两者的区别
// s1是作为字符串常量存储在字符串常量池中的,目的是共享
// s2是作为对象存储在堆中的,它的value为"abc"
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Person p1 = new Person("tom", 12);
Person p2 = new Person("tom", 12);
System.out.println(p1.name == p2.name); // true 对象虽然存储在堆里面,当时对象的属性如果是基础类型,则依然是指向方法区的常量池的
p1.name = "jack";
System.out.println(p1.name == p2.name); // false 跟上面一样 每次修改都需要在常量池中重新指定内存区域
}
@Test
public void test3() {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4); // true ==比较的地址 s4属于字面量的拼接,所以还是在常量池中,是同一个地址
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s6); // false
System.out.println(s5 == s7); // false
System.out.println(s6 == s7); // false
// s5,s6,s7的拼接,都有String对象变量的参与,所以它们是存在堆空间的地址,然后地址再指向常量池中的 "javaEEhadoop" 字符串
System.out.println(s3.equals(s5)); // true 比较的是值
// 常量与常量的拼接结果是在常量池,且常量池中不会存在相同内容的常量
// 只要其中有一个是变量,结果就在堆中
final String s8 = "javaEE"
Srting s9 = s8 + "hadoop";
System.out.println(s3 == s8); // true, 因为使用final定义的s8也是常量,所以也满足常量与常量拼接
// 如果拼接的结果调用 intern() 方法,返回值就在常量池中能够
System.out.println(s3 == s5.intern()); // true
}
}
int length()
: 返回字符串的长度char charAt(int index)
: 返回某索引处的字符boolean isEmpty()
: 判断是否是空字符串String toLowerCase()
: 转换成小写String toUpperCase()
: 转换成大写String trim()
: 返回字符串的副本,忽略前导空白和尾部空白boolean equals(Object obj)
: 比较字符串的内容是否相同boolean equalsIgnoreCase(String s)
: 与equals类似,但忽略大小写String concat(String s)
: 将指定字符串连接到此字符串的结尾int compareTo(String s)
: 比较两个字符串的大小,如果是负数则当前字符串小String substring(int beginIndex)
: 返回一个新的字符串,它是此字符串的从beginIndex开始截取String substring(int beginIndex, int endIndex)
: 返回一个新的字符串,是此字符串从beiginIndex到endIndex的截取,包头不包尾。boolean endsWith(String suffix)
: 此字符串是否以指定的后缀结束boolean startsWith(String prefix)
: 此字符串是否以指定的前缀开始boolean startsWith(String prefix, int toffset):
此字符串从指定索引开始的字符串是否以指定的前缀开始boolean contains(CharSequence s)
: 当前仅当此字符串包含指定的char值序列时返回trueint indexOf(String str)
: 返回指定子字符串在此字符串中第一次出现处的索引int indexOf(Stirng str, int fromIndex)
: 返回指定子字符串在此字符串第一次出现出的索引,从指定的索引开始int lastIndexOf(String str)
: 返回指定子字符串在此字符串中最后一次出现处的索引int lastIndexOf(String str, int fromIndex)
: 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。indexOf
和 lastIndexOf
如果未找到都返回-1String replace(char oldChar, char newChar)
: 返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有oldChar得到的Stirng replace(charSequence target, CharSequence replacement)
: 使用指定的字面值替换此字符串中所有匹配字面值目标序列的子字符串String replaceAll(String regex, String replacement)
: 使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串String replaceFirst(String regex, String replacement)
:使用给定的replacement替换此字符串匹配给定的正则表达式的第一个子字符串boolean matches(String regex)
: 告知此字符串是否匹配给定的正则表达式String[] split(String regex)
: 根据给定正则表达式的匹配拆分此字符串String[] Split(String regex, int limit)
: 根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部放到最后一个元素中。import org.junit.Test;
import java.util.Arrays;
public class StringTest2 {
@Test
public void test1() {
/**
* String --> 基本数据类型、包装类之间的转换
*
* 调用包装类的静态方法 parseXxx(str)
*/
String s1 = "123";
int num = Integer.parseInt(s1);
/**
* 基本数据类型、包装类之间的转换 --> String
*
* 调用String重载过的valueOf方法 或者将其与空串做+运算
*/
String s2 = String.valueOf(num);
String s3 = num + "";
}
@Test
public void test2() {
/**
* String --> char[] 之间的转换
*
* 调用String的实例方法toCharArray
*/
String s1 = "abc";
char[] charArray = s1.toCharArray();
/**
* char[] --> String 之间的转换
*
* 将char[]传给String的构造函数
*/
char[] arr = new char[]{'h', 'e', 'l', 'l', 'o' };
String s2 = new String(arr);
}
@Test
public void test3() {
/**
* String --> byte[] 之间的转换
*
* 调用String的实例方法getBytes
*/
String s1 = "abc";
byte[] b = s1.getBytes();
System.out.println(Arrays.toString(b)); // [97, 98, 99]
/**
* byte[] --> String 之间的转换
*
* 将byte[]传给String的构造函数
*/
String s2 = new String(b);
System.out.println(s2); // abc
}
}
import org.junit.Test;
/**
* String 、StringBuffer 、StringBuilder三者的异同
*
* String: 不可变的字符序列;底层使用char[]存储;效率最差,每次不同都会新造
* StringBuffer: 可变的字符序列;线程安全的,效率低;底层使用char[]存储
* StringBuilder: 可变的字符序列;线程不安全,效率高(jdk5.0新增的);底层使用char[]存储
* 效率从高到低:StringBuilder > StringBuffer > String
*/
public class StringBufferBuilderTest {
@Test
public void test1() {
StringBuffer s1 = new StringBuffer("abc");
s1.setCharAt(0, 'm');
System.out.println(s1); // "mbc" 不同于String,这里的s1被改变了
// 源码分析:
String str = new String(); // char[] value = new char[0]
String str1 = new String("abc"); // char[] value = new char[]{'a', 'b', 'c'}
StringBuffer sb1 = new StringBuffer(); // char[] value = new char[16]; 底层创建了一个长度16的数组
System.out.println(sb1.length()); // 0 但是长度还是0 即关心的还是有效字符串,length方法返回的是count而不在是value.length
sb1.append('a'); // 等同 value[0] = 'a'; // 每次append的时候 count就会++
sb1.append('b'); // 等同 value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc"); // char[] value = new char["abc".length() + 16]
System.out.println(sb2.length()); // 3
// 如果要添加的字符超过了16个,那底层数组就放不下了,就需要扩容
// 扩容为原来的两倍再加2 int newCapacity = (value.length << 1) + 2;
// 同时将原有字符数组中的字符赋值到新的数组中
// 所以开发中,如果明知道字符串会经常变化 建议使用new StringBuffer(int capacity) 指定一个合适的长度
}
@Test
public void test2() {
/**
* StringBuffer 常用的方法
*
* StringBuffer append(xx): 用于字符串拼接
* StringBuffer delete(int start, int end): 删除指定位置的内容
* StringBuffer replace(int start, int end, String str): 将[start, end) 位置替换为str
* StringBuffer insert(int offset, xxx): 在指定位置插入xxx
* int indexOf(String str) 与String indexOf 作用一样,下面几个方法也一样
* String subString(int start, int end)
* int length()
* char charAt(int n)
* void setCharAt(int n, char c) 修改指定位置的元素
*/
StringBuffer s1 = new StringBuffer("abc");
s1.append(1); // 可以append其他类型,不一定是字符串/字符
s1.append('1');
System.out.println(s1); // "abc11"
s1.delete(2, 4);
System.out.println(s1); // "ab1"
s1.replace(1, 2, "d");
System.out.println(s1); // "ad1"
s1.insert(1, "bc");
System.out.println(s1); // "abcd1"
s1.insert(4, false);
System.out.println(s1); // "abcdfalse1"
}
}
import org.junit.Test;
public class StringTest {
@Test
public void sameTest() {
System.out.println(Arrays.toString(getMaxSameString("abcdehelloda", "ca0hellowlloda"))); // [hello, lloda]
}
public String[] getMaxSameString(String str1, String str2) {
if (str1 != null && str2 != null) {
StringBuffer sBuffer = new StringBuffer();
String maxStr = "";
String minStr = "";
if (str1.length() >= str2.length()) {
maxStr = str1;
minStr = str2;
} else {
maxStr = str2;
minStr = str1;
}
int length = minStr.length();
for (int i = 0; i < length; i++) {
// 第一次内循环 比较整个子串
// 第二次内循环 比较长度为 整个子串-1 的截取子串 (0, length -1) (1, length)
// 第三次内循环 比较长度为 整个子串-2 的截取子串 (0, length - 2) (1, length -1) (2, length)
// ....
for (int start = 0, end = length - i; end <= length; start++, end++) {
String subStr = minStr.substring(start, end);
if (maxStr.contains(subStr)) {
sBuffer.append(subStr+ ",");
// 匹配到了目前最长的子串 不结束循环 继续寻找 看是否有另外的最长相同子串
// 比如此例中的 hello 和 lloda 都属于最长子串 都是5个相同的
}
}
// 因为比较长度是从最长依次递减,所以当找到的第一个被append进入的就能找到的最长的子串数组,此时结束外循环
// 没必要往下进行比较更短一个的了
if (sBuffer.length() != 0) {
break;
}
}
// 替换最后一个逗号为空,然后再通过切割中间的逗号
String[] split = sBuffer.toString().replace(",&", "").split("\\,");
return split;
}
return null;
}
}