1.内存部署
public static void StringInit() {
String str = "hello";
System.out.println(str);
String str2 = new String("hello");
System.out.println(str2);
char[] ch = {
'h', 'e', 'l', 'l', 'o'};
String str3 = ch.toString();
System.out.println(str3);
}
ctrl+鼠标:点击String,我们会发现一个String的构造方法
ctrl+鼠标再点击value会发现这个value是被final修饰String一个实例成员变量字符数组,隶属于对象
this.value数组存储的形参中的value值。此时的value存储的时常量池中字符串的地址【为什么是地址:因为当字符串加载的时候,都会加载到常量池中。示例代码中String str = “hello"已经在常量池中加载,因此new String(“hello”)不需要额外消耗资源去加载常量池的"hello”。即使没有第一个的赋值影响,new String也会再次进行常量池加载】
因此我们每次new String(“xxx”)时创建的字符串
public static void StringCompare() {
/**
* JDK1.7开始,字符串常量池 被挪到了 堆 中
*/
String str1 = "hello";
String str2 = new String("hello");
String str3 = "hello";
System.out.println(str1 == str2);//false:== 比较的是引用
System.out.println(str1 == str3);//true:常量池中已经有了hello,因此不用继续放"hello"
String str4 = "hel" + "lo";// 编译时期已经被处理为"hello"
String str5 = new String("hel" + "lo");
System.out.println(str1 == str4);//true
System.out.println(str1 == str5);//false
final int a = 10;
int c = a + 30;
String str6 = str1;
str6 = "world";//只是改变了str6的指向,并没有达到修改只想内容的效果。因为String的常量不可被修改【传引用不会修改值,对于数组而言拿引用修改值才可以达到指向内容修改的效果】
str6 = 'w' + str1.substring(1);//一个'h'拼接str1从第二个元素开始到最后一个元素[包含最后一个元素]截止所有字符串。但是依旧没有修改str1的内容
/*
null.equals(str): 会报错
而str.equals(null): 不会报错
因此建议str.equals(null)来比较。将被比较的的对象放入equals内部,已经确定的对象放在equals外部
*/
System.out.println(str1.equals(str5));//true: equals比较的是内容而不是引用
/**
* intern手动入池,从现象上看的
* 当前的这个字符串在常量池中是否存在?如果存在,把常量池中的引用赋值给当前的引用类型变量
*/
String str7 = new String("hel" + "lo").intern();
System.out.println(str1 == str7);//true
/*
如下代码会残生大量临时变量在常量池中
后续中用StringBuffer或者StringBuilder拼接
*/
/*String str8 = "hello";
for (int i = 0; i < 1000; i++) {
str8 += i;
}*/
}
内存布局
常量在编译时的状态
javac -encoding 编码格式 文件名.java
javap -c 文件名.class
3.反射机制
public static void reflect() throws NoSuchFieldException, IllegalAccessException {
// 利用反射--》自省的过程
String str = "Hello";
Class cl = String.class;
Field field = cl.getDeclaredField("value");
field.setAccessible(true);
char[] val = (char[]) field.get(str);
val[0] = 'g';
System.out.println(str);
}
2.常用方法
public static void chararray_To_String() {
/*
字符数组--》字符串
*/
char[] ch = {
'a', 'b', 'c', 'd', 'e'};
String str = ch.toString();// 字符数组.toString全部转换
String str2 = new String(ch);// new String(字符数组)全部转换
String str3 = new String(ch, 1, 3);// new String(起始位置, 偏移量)部分转换或者全部转换
System.out.println(str);
System.out.println(str2);
System.out.println(str3);
}
[C@1540e19d
abcde
bcd
public static void String_To_char() {
/*
字符串--》字符
*/
String str4 = "Hello";
char ch2 = str4.charAt(0);// 把字符串转换为字符,取字符
}
ch2: H
Hello
public static void String_To_chararray() {
/*
字符串--》字符数组
*/
String str = "Hello";
char[] ch = str.toCharArray();
}
[H, e, l, l, o]
public static void byte_To_String() {
/*
字节数组--》字符串
*/
byte[] bytes = {
97, 98, 99, 100};
String str = bytes.toString();
String str2 = new String(bytes, 1, 3);
System.out.println(str);
System.out.println(str2);
}
[B@1540e19d
bcd
public static void String_To_bytearray() {
/*
字符串--》字节数组
那么何时使用 byte[], 何时使用 char[] 呢?
byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合针对二进制数据来操作.
char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候.
*/
String str = "Hello";
// byte[] bytes = str.getBytes("utf8");
byte[] bytes2 = str.getBytes();
System.out.println(Arrays.toString(bytes2));
}
[72, 101, 108, 108, 111]
带有@Deprecated注解说明已经被弃用
public static void String_equals() {
/*
字符串内容比较
*/
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equals(str2)); // false
System.out.println(str1.equalsIgnoreCase(str2)); // true
}
equals源码可知:因为是一个一个内容进行比较
public static void String_compareTo() {
/*
字符串大小比较
*/
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.compareTo(str2));
}
32[有一定的规律,ASCII值差]
字符串比较大小函数,是String自带重写compare函数之后的效果。需要注意他的返回值类型是int
public static void String_replace() {
/*
replace 和 replaceAll 几乎没有差别
*/
String str = "helloworld";
System.out.println(str.replace("l", "_"));
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));// 替换第一个出现的
}
he__owor_d
he__owor_d
he_loworld
public static void String_substring() {
/*
字符串截取
*/
String str = "helloworld";
System.out.println(str.substring(5));// 从此位置开始截取到结束位置
System.out.println(str.substring(0, 5));//[0, 5)
}
world
hello
public static void String_trim() {
/*
字符串去空白
*/
String str = " hello world ";
System.out.println("[" + str + "]");
System.out.println("[" + str.trim() + "]");
}
[ hello world ]
[hello world]
public static void String_contains() {
/*
字符串查找
*/
String str = "helloworld";
System.out.println(str.contains("world")); // true
System.out.println(str.indexOf("world")); // 5,w开始的索引
System.out.println(str.indexOf("bit")); // -1,没有查到
System.out.println(str.indexOf("world", 3));//无论几开始,都是0计算下标
System.out.println(str.lastIndexOf("world"));
System.out.println(str.lastIndexOf("world", 90));
}
true
5
-1
5
5
5
public static void String_with() {
/*
字符串开头或者结尾匹配
*/
String str = "**@@helloworld!!";
System.out.println(str.startsWith("**")); // true
System.out.println(str.startsWith("@@", 2)); // ture
System.out.println(str.endsWith("!!")); // true
}
true
true
true
public static void String_split() {
/*
字符串切割
*/
String str = "hello world hello bit";
String[] result = str.split(" "); // 按照空格拆分
for (String s : result) {
System.out.println(s);
}
String str2 = "192.168.1.1";
String[] result2 = str2.split("\\.");
for (String s : result2) {
System.out.println(s);
}
// 分割多次
String str3 = "name=zhangsan&age=18";
String[] result3 = str3.split("&");
for (int i = 0; i < result3.length; i++) {
String[] temp = result3[i].split("=");
System.out.println(temp[0] + " = " + temp[1]);
}
}
hello
world
hello
bit
192
168
1
1
name = zhangsan
age = 18
下图是字符串切割函数源码。我们需要注意红色圈圈部分特殊字符需要用"\\"进行处理
说明我们字符串切割的split返回的是一个String[] 字符串数组
public static void String_others() {
/*
字符串其它操作
*/
String str = "HEllo";
System.out.println(str.toLowerCase());// 全部转换为 小写
System.out.println(str.toUpperCase());// 全部转换为 大写
System.out.println(str.length());
System.out.println(str.isEmpty());// ""空;null指向为空
}
hello
HELLO
5
false
/**
* String、StringBuffer、StringBuilder的区别:
* 1.String的拼接会产生大量的临时变量,StringBuilder和StringBuffer不会
* Spring拼接会被优化为SpringBuilder
*
*
* String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
* StringBuffer与StringBuilder大部分功能是相似的
* StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安
* 全操作
*/
public static void Buffer_Builder() {
/*
StringBuilder和StringBuilder
*/
String str = "";
for (int i = 0; i < 3; i++) {
str += i;
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 4; i++) {
stringBuilder.append(i + "");
}
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Hello");
System.out.println(stringBuffer.reverse());
System.out.println(stringBuffer.delete(0, 1));
System.out.println(stringBuilder.insert(0, "GG"));
}
olleH
lleH
GG0123
源码说明StringBuilder不存在synchronized修饰来限定线程同步所以不安全而StringBuffer是安全的
String hello说明创建了一个hello的字符串
new:说明创建了一个对象,后边的StringBuilder说明是StringBuilder对象
invokespecial:说明调用了什么方法,后边的StringBuilder说明调用了StringBuilder方法;后边的几个调用的是StringBuilder的append方法
最后因为要打印,所以需要经过otString转换后才能输出字符串
此处的反编译是代码中StringBuilder和StringBuffer代码中的部分反编译结果图