目录
String字符串
文档注释
String常量池
String创建对象问题
length()
indexOf()
substring()
charAt()
trim()
toUpperCase()和toLowerCase()
valueOf()
startsWith()和endsWith
练习:截取域名
正则表达式
matches()
split()
replaceAll()
StringBuilder可变字符串
String、StringBuffer和StringBuilder的区别
String字符串
多个字符组成的一串数据,例如 “abc” 也可以看成是一个字符数组。
而通过 API我们又可以知道
A:字符串字面值“abc”也可以看成是一个字符串对象
B:字符串是常量,一旦被赋值,就不能改变,String类默认被final修饰。但是字符串引用可以重新被赋值,不过该引用指向的是后来被赋的值。
String类的构造方法可以将 字节、字符数组、字符串常量(全部或者部分)转换为字符串类型。
public static void main(String[] args) {
// 把字节数组转换成字符串
byte[] bt = {97,98,99,100,101};
String str = new String(bt);
System.out.println(str);// abcde
//把字节数组的一部分转换成字符串
//public String(byte bytes[], int offset, int length){}
String str1 = new String(bt,0,2);
System.out.println(str1);// ab
}
}
package string;
public class StringDemo2 {
public static void main(String[] args) {
/**
* String类默认被final修饰,字符串是常量,一旦被赋值,就不能改变,
* 但是字符串引用可以重新被赋值,不过该引用指向的是后来被赋的值。
*/
String s ="ab";
s = "cd";
System.out.println(s);// cd
/**
* +号特性:
* 字符串前字面量可直接相加得出结果,字符串后从左到右依次追加字符串。
*/
s = 1 + 2 + s + 5 + 6;
System.out.println(s);// 3cd56
}
}
文档注释
文档注释可以在三个地方使用 :
1.类上 在类上面写是用来说明当前类的功能
2.方法上(成员方法,静态方法,构造方法均可)
3.常量上
4.@author Lee Boynton代表作者
@version 1.2.1代表版本号
@see import java.util.Arrays;代表参见
@since JDK1.8 代表JDK版本
public class Demo {
/**
* sayHello中使用的问候语
*/
public static final String INFO = "hello";
/**
* 对给定的用户添加问候语
*
* @param name 给定的用户的名字
* @return 返回含有问候语的字符串
*/
public String sayHello(String name) {
return "hello!" + name;
}
}
String常量池
String常量池是java对字符串的一个优化措施, 在堆内存中开辟的一段空间,用于缓存所有使用字面量形式创建的字符串对象。 所以使用相同字面量形式创建的字符串都是重用同一个对象的以减少内存的开销。
String s = "hello"; 创建实例过程:
- 在字符串常量中查找是否存在内容为"hello"的字符串对象
A:若存在,让s直接引用该对象
B:若不存在,先创建该对象,则直接让s引用该对象注意: String s = “ ”; // 字符串内容为空 String s = null; // 字符串对象为空
String创建对象问题
package string;
/**
* String创建对象问题
* 以下每一条语句都假设为常量池中都没有该字符串,
* 我是为了方便记忆和区分才写到一起。
* @author Jack
*
*/
public class StringNewDemo {
public static void main(String[] args) {
/**
*1. 一个字面量情况:
*在创建这个对象时,会在常量池中看有没有abc这个字符串:
* 如果没有此时还会在常量池中创建一个;
* 如果有则不创建。
* 所以一共创建1个。
*/
String s = "abc";
/**
*2.字面量相加情况:
* 在字符串常量相加时,编译器编译时产生的字节码,会把如 "a"+"b"+"c"优化为“abc”。
* 所以一共创建1个。
*/
String s1 = "a" + "b" + "c";
/**
* 3.new String()情况:
* 在创建这个对象时因为使用了new关键字,所以肯定会在堆中创建一个对象。
* 然后会在常量池中看有没有abc这个字符串:
* 如果没有此时还会在常量池中创建一个;
* 如果有则不创建。
* 所以一共创建2个。
*/
String s2 = new String("abc");
/**
* 4.变量+字面量情况:
* 在变量与常量进行相加时,"+"可以理解为利用加号进行拼接字符串。执行过程如下:
* 1.在底层内部中会生成新的StringBuilder对象,调用SringBuilder中的
* append方法进行拼接。
* 2.最后拼接完成之后会调用StringBuilder.toString()方法返回一个
* String的对象“abcdef”。
* 所以一共创建3个对象。
*/
String s3 ="abc";
String s4 = s3 + "def";
/**
* 5.字面量+变量+字面量情况:
* 在底层内部进行判断时,在未出现变量之前的部分字符串还满足4中的情况,所以会进行自
* 动拼接变成"abcd",出现了变量之后就不符合4中的情况,所以后面的字符串不会进行拼接。
* 所以最后变为了:“abcd”+s5+"gh"+"ij";
* 所以一共创建了5个对象。
*/
String s5 = "ef";
String s6 = "ab" + "cd" + s5 + "gh" + "ij";
/**
* 6.new String()+变量+字面量情况:
* 只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象
* 才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,
* 它所产生的新对象都不会被加入字符串池中。
* new String("今年")在堆中创建1个,在字符串常量池中创建1个;
* s7在字符串常量池中创建1个;
* "2019年。"在字符串常量池中创建1个;
* 相加的内容“今年是2019年。”在字符串常量池中创建1个;
* 所以一共创建了5个对象。
*/
String s7 = "是";
String s8 = new String("今年") + s7 + "2019年。";
/**
* 7.new String(字面量+字面量)情况:
* "ab"字符串常量池中创建1个;
* "cd"字符串常量池中创建1个;
* "abcd"字符串常量池中创建1个;
* "abcd"在堆中创建1个。
* 所以一共创建了4个对象。
* new String(字面量+变量+字面量)同理,一共创建5个对象。
*/
String s9 = new String("ab" + "cd");
/**
* 8.new String()+new String()情况:
* new String("ab")创建2个;
* new String("bc")创建2个;
* 相加的内容"abcd"创建1个;
* 一共创建了5个对象。
*/
String s10 = new String("ab") + new String("cd");
}
}
public class StringDemo {
public static void main(String[] args) {
// ==比较的是地址
String s1 = "123abc";
String s2 = "123abc";// s2重用了s1创建的字符串对象
System.out.println(s1 == s2);// true, s2与s1地址相同
String s3 = "123abc";
System.out.println(s1 == s3);// true
s1 = s1 + "!";// s1改变内容,新建内存,改变引用,不影响其它引用指向
System.out.println(s1 == s2);// false
System.out.println(s1 == s3);// false
System.out.println(s2 == s3);// true
String s4 = new String("123abc");// new新建地址,和s2、s3的地址都不同,而且不会在常量池,只有字面量才会在。
System.out.println(s4 == s2);// false
// 如果要比较字符串内容,用equals方法
System.out.println(s4.equals(s2));// true
/**
* java编译器有一个特性: 当编译期间可以确定某个计算表达式的结果时,编译器会在编译期间就进行计算并将结果编译到字节码文件中,
* 因此下面的代码会被编译器改为: String s5 = "123abc";
*/
String s5 = "123" + "abc";// 都是字面量才可以
System.out.println(s5);// 123abc
System.out.println(s2 == s5);// true
String s = "123";
String s6 = s + "abc"; // 有变量不行
System.out.println(s6);// 123abc
System.out.println(s2 == s6);// false
}
}
length()
int length() 返回当前字符串的长度。
public class LengthDemo {
public static void main(String[] args) {
String str = "我爱Java!";
int len = str.length();// 字符个数方法
System.out.println(len);//7
}
}
indexOf()
int indexOf(String str) 返回给定字符串在当前字符串中的位置,若当前字符串不包含内容时返回值为-1。
public class IndexOfDemo {
public static void main(String[] args) {
// 索引 0123456789012345
String str = "Thinking in Java";
int index = str.indexOf("in");// 返回第一个in索引数字
System.out.println(index);// 2
index = str.indexOf("@");// 查看是否有@字符
System.out.println(index);// -1
/**
* 重载方法可以从指定位置开始检索,第一次出现的位置
*/
index = str.indexOf("in", 3);// 从索引3开始查找
System.out.println(index);// 5
/**
* lastIndexOf()是查找最后一次出现的位置
*/
index = str.lastIndexOf("in");// 从后往前查找
System.out.println(index);// 9
}
}
substring()
String substring(int start,int end) 截取当前字符串中指定范围内的子字符串,两个参数为开始位置与结束位置的下标, 通常javaAPI中使用两个数字表示范围时都是“含头不含尾”的。
public class Substring {
public static void main(String[] args) {
// 索引 01234567890
String line = "www.tedu.cn";
String sub = line.substring(4, 8);// 截取索引4~7的字符
System.out.println(sub);// tedu
/**
* 重载方法:可以只写一个索引,表示从指定位置截取到字符串末尾
*/
sub = line.substring(4);// 从4开始截取到末尾
System.out.println(sub);// tedu.cn
}
}
charAt()
char charAt(int index)返回当前字符串中给定位置对应的字符
public class CharAtDemo {
public static void main(String[] args) {
// 0123456789
String str = "helloworld";
char c = str.charAt(5);// 获取索引为5的第六个字符
System.out.println(c);
}
}
trim()
String trim()去除字符串两边的空白字符,注意中间的空格不能去除
public class TrimDemo {
public static void main(String[] args) {
String str = " Hello Java! ";
String trim = str.trim();
System.out.println(trim);//Hello Java!
}
}
toUpperCase()和toLowerCase()
String toUpperCase() 将当前字符串中的英文部分转换为全大写或全小写
String toLowerCase()
public class ToUpperCaseDemo {
public static void main(String[] args) {
String str = "我爱Java";
String upper = str.toUpperCase();
System.out.println(upper);// 我爱JAVA
String lower = str.toLowerCase();
System.out.println(lower);// 我爱java
/**
* 如果忽略大小写比较两个字符串是否相等,可以全部转换为大写或者全部转换为小写
*/
String line = "56WyX";
String s = "56wyx";
line = line.toUpperCase();// 全部转换为大写
s = s.toLowerCase();// 全部转换为大写
System.out.println(line.equals(s));
}
}
valueOf()
static String valueOf(XXX xxx)
String提供了一组静态的valueOf方法,可以将其他类型转换为字符串,比较常用的是将基本类型转换为字符串
public class ValueOfDemo {
public static void main(String[] args) {
int a = 123;
String s1 = String.valueOf(a);// 操作频繁用
System.out.println(s1);// 123
float f = 123f;
String s2 = String.valueOf(f);
System.out.println(s2);// 123.0
s1 = a + "";// 常用
System.out.println(s1);
}
}
startsWith()和endsWith
boolean startsWith(String str)判断字符串是否以给定字符串开始或结尾
boolean endsWith(String str)
public class StartswithDemo {
public static void main(String[] args) {
String line = "www.tedu.cn";
boolean start = line.startsWith("www.");
System.out.println(start);// true
boolean end = line.endsWith(".cn");
System.out.println(end);// true
}
}
练习:截取域名
public class Test {
public static void main(String[] args) {
String s1 = getHost("www.baidu.com");
String s2 = getHost("http://www.tedu.cn");
String s3 = getHost("www.abc.com.cn");
System.out.println(s1);// baidu
System.out.println(s2);// tedu
System.out.println(s3);// abc
}
public static String getHost(String line) {
int indexStart = line.indexOf(".") + 1;// 检测第一个点的索引+1
int indexEnd = line.indexOf(".", indexStart);// 检测第二个点的索引
String sub = line.substring(indexStart, indexEnd);// 域名索引范围
return sub;// 把结果返回给s1、s2
}
}
正则表达式
实际开发中,经常需要对字符串数据进行一些复杂的匹配、查找、替换等操作。通过“正则表达式”,可以方便的实现字符串的复杂操作。正则表达式是一串特定字符,组成一个“规则字符串”,这个“规则字符串”是描述文本规则的工具。正则表达式就是记录文本规则的代码。
3位数字的表示规则:
第一种,[0-9][0-9][0-9].
第二种,\d\d\d.
第三种,\d{3}.
圆括号():表示分组,可以将一系列正则表达式看作一个整体,分组时用“|”表示“或”关系。如(123|456)表示123或456.
边界匹配:
^表示字符串开始
$表示字符串结束
\b表示单词边界,就是不是单词字符的地方。
matches()
java支持正则表达式的方法之一: boolean matches(String regex)
使用给定的正则表达式验证字符串的内容是否符合格式要求,符合则返回true
public class MatchesDemo {
public static void main(String[] args) {
String email = "lsj@qq.com";
String regex = "[a-zA-Z0-9]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";// .在正则表达式里有特殊含义,表示任意字符,因此要用\\.
boolean matches = email.matches(regex);
if (matches) {
System.out.println("是邮箱");
} else {
System.out.println("不是邮箱");
}
}
}
split()
String支持正则表达式二: String[] split(String regex)
将当前字符串按照满足正则表达式的部分进行拆分,将拆分后的字符串以数组形式返回。
public class SplitDemo {
public static void main(String[] args) {
String str = "abc123def456ghi789jkl";
// 拆分成所有字母部分
String[] data = str.split("[0-9]+");
System.out.println(data.length);// 4
for (int i = 0; i < data.length; i++) {
System.out.println(data[i]);// abc def ghi jkl
}
}
}
replaceAll()
String支持正则表达式三: String replaceAll(String regex,String str)
将当前字符串中满足正则表达式的部分替换为给定的字符串
public class ReplaceAllDemo {
public static void main(String[] args) {
String str = "abc123def456ghi789jkl";
// 将数字部分换成"#NUMBER#"
str = str.replaceAll("[0-9]+", "#NUMBER#");
System.out.println(str);
}
}
StringBuilder可变字符串
java.lang.StringBuilder 字符串的优化是针对重用的,而频繁修改字符串会降低性能并造成大量内存开销,因此字符串本身不适合频繁修改。
为此,java提供了专门用来修改字符串的API:StringBuilder,其内部维护一个可变的char数组(没有final修饰),
所以字符串内容都是在这个char数组上进行,因此开销小,性能好。
先实例化一个StringBuilder可变字符串的变量引用,然后用这个引用调方法,就不需要再定义个匹配的返回值类型变量去接操作后的数据。
StringBuilder也可以用String的方法,不过要定义匹配的返回值类型去接数据。
public class StringBuilderDemo {
public static void main(String[] args) {
String str = "努力学习java";
StringBuilder builder1 = new StringBuilder();// 默认表示空字符串("")
/**
* 将给定的字符串内容复制到StringBuilder中,使其表示该字符串并可进行修改。
*/
StringBuilder builder = new StringBuilder(str);
/**
* 努力学习java,为了找个好工作!
*append()方法是将给定的内容拼接到字符串末尾。
*/
builder.append(",为了找个好工作!");// 字符串追加方法
str = builder.toString();// 转换为字符串
System.out.println(str);
/**
* 努力学习java,为了找个好工作!
* 努力学习java,就是为了改变世界!
* replace()方法是将指定范围内的字符串替换为给定的字符串
*/
builder.replace(9, 16, "就是为了改变世界");
System.out.println(builder.toString());
/**
* 努力学习java,就是为了改变世界!
* ,就是为了改变世界!
* delete() 刪除指定范围内的字符串
*/
builder.delete(0, 8);// 索引范围,含头不含尾
System.out.println(builder.toString());
/**
* ,就是为了改变世界!
* 活着,就是为了改变世界!
* indert() 插入字符串
*/
builder.insert(0, "活着");// 0索引之前,插入该字符串
System.out.println(builder);
}
}