从概念上将,Java字符串就是Unicode字符序列,例如字符串 "Java\u2122"由五个Unicode字符 J,a,v,a和™组成
String s="";
String str="Hello";
String类在我们的java.lang包下
//我们JDK1.8下String的部分源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
字符串的不可变不代表引用不可变
String str="hello";
str="hello world";
// 方式一
String str = "Hello Bit";
// 方式二
String str2 = new String("Hello Bit");
// 方式三
char[] array = {'a', 'b', 'c'};
String str3 = new String(array);
//方式四
String str4= String.valueOf(10);
int x = 10 ;
int y = 10 ;
System.out.println(x == y);
// 执行结果
true
代码1
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 执行结果
true
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 执行结果
false
池的思想
也就是共享设计模式,为了节省空间(因为内存十分宝贵),字符串产生之后大部分情况都是用来进行输出处理,只打印,一个对象就够了,数据库的连接池和线程池都是这样的思想
如 “Hello” 这样的字符串字面值常量, 也是需要一定的内存空间来存储的. 这样的常量具有一个特点, 就是不需要
修改(常量嘛). 所以如果代码中有多个地方引用都需要使用 “Hello” 的话, 就直接引用到常量池的这个位置就行
了, 而没必要把 “Hello” 在内存中存储两次.
Java 中要想比较字符串的内容, 必须采用String类提供的equals方法.
equals 使用注意事项
现在需要比较 str 和 “Hello” 两个字符串是否相等, 我们该如何来写呢?
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者这样写也行
// 执行结果
true
String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
String str = null;
// 方式一
System.out.println(str.equals("Hello")); // 执行结果 抛出 java.lang.NullPointerException 异
常
// 方式二
System.out.println("Hello".equals(str)); // 执行结果 false
根据上面的比较操作,我们对常量池有个认识,现在就介绍一个入池intern()操作
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";// javac 在编译期间的优化,结果已经在编译期确定为ab
String s4 = s1 + s2;// new StringBuilder().append("a").append("b").toString() new String("ab")
String s5 = "ab";
String s6 = s4.intern();
// 问
System.out.println(s3 == s4); //false
System.out.println(s3 == s5);//true
System.out.println(s3 == s6);//true
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
System.out.println(x1 == x2); //1.6false 1.8false
String x2 = new String("c") + new String("d");
x2.intern();
String x1 = "cd";
System.out.println(x1 == x2); //1.6false 1.8true
变量
拼接的原理是 StringBuilder (1.8)常量
拼接的原理是编译期优化当字符串常量池有对应的字符串常量
当字符串常量池没有对应的字符串
jdk1.6 StringTable 位置是在永久代中,1.8 StringTable 位置是在堆中。
为什么要这样
因为我们永久代的回收效率很低,只有FULL GC才会触发永久代的回收(FULL GC在老年代空间不足才会触发)
StringTable存储着我们的字符串常量,我们的字符串常量在程序中应用的次数很多,所以要及时对StringTable进行回收
String提供的API都不是在原本的字符串进行操作,而是返回一个新的字符串对象
Java跟许多程序设计语言一样,也是支持+来拼接两个字符串
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";// javac 在编译期间的优化,结果已经在编译期确定为ab
String s4 = s1 + s2;// new StringBuilder().append("a").append("b").toString() new String("ab")
int age=13;
String rating="PG"+13;
如果需要将多个字符串放在一起,用一个界定符分隔,可以使用静态方法join
String all=String.join(" / ","s","m","l");
//all is the String "s / m / l"
Java11还提供了一个repeat方法
String repeated="Java".repeat(3);// repeated is "JavaJavaJava"
从一个完整的字符串之中截取出部分内容
String str = "helloworld" ;
System.out.println(str.substring(5));//hello
System.out.println(str.substring(0, 5));//hello
我们上面知道有equals是用来比较两个字符串的内容是否相同
不区分大小写比较 equalsIgnoreCase()
String str1 = "hello" ;
String str2 = "Hello" ;
System.out.println(str1.equals(str2)); // false
System.out.println(str1.equalsIgnoreCase(str2)); // true
在String类中compareTo()
方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内容:
System.out.println("A".compareTo("a")); // -32
System.out.println("a".compareTo("A")); // 32
System.out.println("A".compareTo("A")); // 0
System.out.println("AB".compareTo("AC")); // -1
System.out.println("刘".compareTo("杨"));//比较刘和杨这两个字符对应的unicode值,返回刘-杨的unicode的差值
compareTo()是一个可以区分大小关系的方法,是String方法里是一个非常重要的方法。
字符串的比较大小规则, 总结成三个字 “字典序” 相当于判定两个字符串在一本词典的前面还是后面. 先比较第一
个字符的大小(根据 unicode 的值来判定), 如果不分胜负, 就依次比较后面的内容
最好用的就是contains()
String str = "helloworld" ;
System.out.println(str.contains("world")); // true
该判断形式是从JDK1.5之后开始追加的,在JDK1.5以前要想实现与之类似的功能,就必须借助、indexOf()方法完
成。
使用indexOf()
String str = "helloworld" ;
System.out.println(str.indexOf("world")); // 5,w开始的索引
System.out.println(str.indexOf("bit")); // -1,没有查到
if (str.indexOf("hello") != -1) {
System.out.println("可以查到指定字符串!");
}
在进行查找的时候往往会判断开头或结尾endWith和startWith
。
String str = "**@@helloworld!!" ;
System.out.println(str.startsWith("**")); // true
System.out.println(str.startsWith("@@",2)); // ture 后面一个参数决定从那个位置开始计算
System.out.println(str.endsWith("!!")); // true
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
String str = "hello world hello bit" ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) { //返回的是一个字符串数组
System.out.println(s);
}
String str = "hello world hello bit" ;
String[] result = str.split(" ",2) ;//说明最多只能分为两个子字符串
for(String s: result) {
System.out.println(s);
}
//hello
//world hello bit
拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.
拆分IP地址
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {
System.out.println(s);
}
字符串的替换处理
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));//替换全部的_
System.out.println(str.replaceFirst("l", "_"));//替换第一个_
注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串
trim()
方法的使用,trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等 )
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");
//[ hello world ]
//[hello world]
大小写转换
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
这两个函数只转换字母。
字符串length()
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.length());
注意:数组长度使用数组名称.length属性,而String中使用的是length()方法,而且我们的length()返回的是字符串代码单元的个数
isEmpty()
方法 判断一个字符串对象是不是空串
System.out.println("hello".isEmpty());
System.out.println("".isEmpty());
System.out.println(new String().isEmpty());
//判断是不是空串
if(str.length()==0)
if(str.equals(""))
//判断是不是null串
if(str==null)
我们String提供了将字符转换成字符串的构造方法
,和将字符串转换为字符数组的toCharArray()
String str = "helloworld" ;
// 将字符串变为字符数组
char[] data = str.toCharArray() ;
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+" ");
}
// 字符数组转为字符串
System.out.println(new String(data)); // 全部转换
System.out.println(new String(data,5,5)); // 部分转换
查找指定字符串指定位置的字符 charAt()
String str = "hello" ;
System.out.println(str.charAt(0)); // 下标从 0 开始
// 执行结果
System.out.println(str.charAt(10));
// 执行结果
产生 StringIndexOutOfBoundsException 异常
我们String提供了将字节转换成字符串的构造方法
,和将字符串转换为字节数组的getBytes()
String str = "helloworld" ;
// String 转 byte[]
byte[] data = str.getBytes() ;
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+" ");
}
// byte[] 转 String
System.out.println(new String(data));
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,而且因为如果频繁的对字符串进行拼接,会不断产生新的对象,比较消耗内存,所以提供StringBuffer和StringBuilder类。
StringBuffer 和 StringBuilder 大部分功能是相同的,主要介绍 StringBuffer
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法:
public synchronized StringBuffer append(各种数据类型 )
使用提供的append方法来增加字符串的内容,这里不会产生新的对象,一种指向着一个对象
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuffer:利用StringBuffer的构造方法或append()方法
StringBuffer变为String:调用toString()方法
String str1 = " hello world " ;
StringBuffer sb=new StringBuffer(str);
sb=sb.append(123);
String str2=sb.toString();
字符串反转 reverse
字符串反转
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.reverse());
删除操作 delete
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 10)); //hello
插入操作insert
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 10).insert(0, "你好")); // 你好hello