本届目标:
1.认识String类
2.了解String类的基本用法
3.熟练掌握String类的常见操作
4.认识字符串常量池
5.认识StringBuffer 和 StringBuilder
1.String类的重要性
在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类.
在开发和校招笔试中,字符串也是常客,比如:
字符串转整型数字
字符串相加
而且在面试中也频繁被问到,比如:String,StringBuff和StringBuilder之间的区别等
2.常用方法
2.1字符串构造
String类提供的构造方式非常多,常用的就以下三种:
public static void main(String[] args){
方法一:
//使用常量串构造
String s1 = "hello bit";
System.out.println(s1);
方法二:
//直接newString对象
String s2 = new String("hello bit");
System.out.println(s2);
方法三:
//使用字符串数组进行构造
char[] array = {'h','e','l','l','o','b','i','t'};
String s3 = new String(array);
System.out.println(s3);
}
注意:
1.String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:
public static void main(String[] args){
//s1和s2引用的是不同对象,s1和s3引用的是同一对象
String s1 = new String("hello");
String s2 = new String("world");
String s3 = s1;
System.out.println(s1.length()); //获取字符串长度--输出5
System.out.println(s1.isEmpty()); //如果字符串长度为0,返回true,否则返回false
}
2.在java中""引起来的也是String类型对象.
//打印"hello"字符串(String对象)的长度
System.out.println("hello".length());
2.2String对象的比较
字符串的比较是常见操作之一,比如:字符串排序,Java中总共提供了4种方式:
字符串比较大小的理解:
1."=="比较是否引用同一个对象
(注意:1'对于内置类型,==比较的是变量中的值;
2'对于引用类型==比较的是引用中的地址。)
public static void main(String[] args){
int a = 10;
int b = 20;
int c = 10;
//对于基本类型变量,==比较两个变量中存储的值是否相同
System.out.println(a==b); //false
System.out.println(a==c); //true
//对于引用类型变量,==比较两个引用变量引用的是否为同一个对象,很明显s1和s2是不同的两
个对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
//结果
System.out.println(s1==s2); //false 再次注意,对于引用类型==比较的是引
用中的地址
System.out.println(s2==s3); //false
System.out.println(s1==s4); //true
}
2.boolen equals(Object anObject)方法:按照字典序比较
字典序:字符大小的顺序:
String类重写了父类中Object中的equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2)
public boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString=(String)anObject;
int n = value.length;
//3.this和anObject两个字符串的长度是否相同,是,则继续比较,否则返回false
if(n==anotherString.value.length){
char v1[] = value;
cahr v2[] = anotherString.value;
int i = 0;
//4.按照字典序,从前往后逐个字符进行比较
while(n--!=0){
if(v1[i]!=v2[i]
return false;
i++;
}
return true;
}
}
return false;
}
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("Hello");
// s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false
System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // false
//equals比较:String对象中的逐个字符
//虽然s1与s2引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s3));//false
}
3.int compareTo(String s)方法:按照字典序进行比较(结果不一定是=1或-1
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型,具体比较方法:
1.先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值(用ASCII来计算)
2.如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public static void main(String[] args){
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); //不同输出字符差值 -1
System.out.println(s1.compareTo(s3)); //相同输出0
SYstem.out.println(s1.compareTo(s4)); //前k个字符完全相同,输出长度差值-3
}
4. int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写比较(转为同为大写或同为小写)
public static void main(String[] args)P{
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABC");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2));//不同输出字符差值为-1
System.out.println(s1.compareToIgnoreCase(s3));//相同输出0
System.out.println(s1.compareToIgnoreCase(s2));//前k个字符完全相同,输出长度差
值为-3
2.3字符串查找
字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法:
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
//下标从0开始
//从左往右找首次出现的字符(串)
System.out.println(s.charAt(3)); // 'b'
System.out.println(s.indexOf('c')); // 6
System.out.println(s.indexOf('c', 10)); // 15
System.out.println(s.indexOf("bbb")); // 3
System.out.println(s.indexOf("bbb", 10)); // 12
//从右往左找首次出现的字符(串)
System.out.println(s.lastIndexOf('c')); // 17
System.out.println(s.lastIndexOf('c', 10)); // 8
System.out.println(s.lastIndexOf("bbb")); // 12
System.out.println(s.lastIndexOf("bbb", 10)); // 3
public static void main(String[] args){
//数字转字符串
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
String s4 = String.valueOf(new Strudent("Hanmeimei",18);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println("=================================");
//字符串转数字
//注意:Integer,Double等是Java中包装类型
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);
}
2.大小写转换( .toUpperCase() .toLowerCase() )
public static void main(String[] args){
String s1 = "hello";
String s2 = "HELLO";
//小写转大写.toUpperCase()
System.out.println(s1.toUpperCase());
//大写转小写.LowerCase()
System.out.println(s2.LowerCase());
}
3.字符串转数组( .toCharArray() )
public static void main(String[] args){
String s = "hello";
//字符串转数组
char[] ch = s.toCharArrar();
for(int i= 0;i<ch.length;i++){
System.out.println(ch[i]);
}
System.out.println();
//数组转字符串
String s2 = new String(ch);
System.out.println(s2);
}
4.格式化( .format(("%d-%d-%d", 2019, 9,14) )
public static void main(String[] args){
String s = String.format("%d-$d-%d",2019,9,14);
System.out.println(s);
}
2.5字符串替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
方法1: String replaceAll(String regex,String replacemernt) --------替换所有的指定内容
方法2: String replaceFirst(String regex,String replacement)--------替换首个内容
String str = "helloworld";
System.out.println(str.replaceAll("l","_"); //结果:he__owor_d
System.out.println(str.replaceFirst("l","_"); //结果:he_loworld
注意事项:由于字符是不可变对象,替换时不修改当前字符串,而是产生一个新的字符串
代码示例:实现字符串的拆分处理:
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);
}
拆分是特别常用的操作,一定要重点掌握,另外有些特殊字符作为分割符可能无法正确切分,需要加上转义 .
代码示例:拆分IP地址
String str = "192.168.1.1";
String[] result = str.split("\\."); //按照.来拆分
for(String s:result){
System.out.println(S);
}
注意事项:
1.字符"|","*","+"都得加上转义字符,前面加上"\\"
2.而如果是"\",那么就得写成"\\\\"
3.如果一个字符串中有多个分隔符,可以用"|"作为连字符
代码示例:多次拆分
String str = "name=zhangsan&age=18";
String[] result = str.split("&"); //遇到&拆分
for(int i=0;i<result.length;i++){
String[] temp = result[i].split("="); //遍历字符串长度,遇到=拆分
System.out.println(temp[0]+"="+temp[1]); //第一次循环name=zhangsan
//第二次循环age=18
}
这种代码在以后的开发之中会经常出现
2.7字符串截取
从一个完整的字符串之中截取出部分内容.可用方法如下:
1.方法一: String substring(int beginIndex) //(开始的下标) --------从指定索引截取到结尾
2.方法二: String substring(int beginnIndex,int endIndex) //(开始的下标,结束的下标)------截取部 分内容
代码示例:观察字符串截取
String str = "helloworld";
System.out.println(str.substring(5));//从第5个元素开始截取到结尾
System.out.println(str.substring(0,5));//从第0个元素开始,到第5个元素结束来截取
注意事项:
1.索引从0开始
2.注意前闭后开区间的写发[ , ) ,substring(0,5)表示包含0号下标的字符,不包含5的字符
2.8其他操作方法
方法1:String trim() -----------------去掉字符串中的左右空格,保留中间空格
方法2:String toUpperCase()-------字符串转大写
方法3:String toLowerCase()------字符串转小写
代码示例:观察trim()方法的使用
String str =" hello world ";
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");
trim会去掉字符串开头和结尾的空白字符(空格,换行,制表符等)
代码示例:大小写转换
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
这两个函数只转换字母
2.9字符串的不可变性
String是一种不可变对象,字符串中的内容是不可改变的,字符串不可被修改,是因为:
1.String 类在设计时就是不可改变的,String类实现描述中已经说明了
String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出
1.String类被final修饰,表明该类不能被继承
2.value被final修饰,表明value自身的值不能改变,及不能引起其他字符数组,但是其引用空间中的内容可以修改.
2.所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
比如replace方法
纠正:网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变.
这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修饰
final修饰类表明该类不想被继承,final修饰引用类型表明引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的
public static void main(String[] args){
final int array[] ={1,2,3,4,5);
array[0] = 100;
System.out.println(Arrays.toString(array));
array=new int[]{14,5,6}; //此行编译报错:Error:java:无法为最终变量array分配值
}
为什么String要设计成不可变的?(不可变对象的好处是什么?)(选学)
1.方便实现字符串对象池.如果String可变,那么对象池就需要考虑写时拷贝的问题了
2.不可变对象是线程安全的
3.不可变对象更方便缓存hash code,作为key时可以跟高效的保存到HashMap中
那如果想要修改字符串中的内容,该如何操作嗯?
2.10字符串修改
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下
public static void main(String[] args){
String s="hello";
s+="world";
System.out.println(s); //输出:hello world
}
但是这种方式不推荐使用,因为其效率非常低,中间创建了好多临时变量
public static void main(String[] args) {
long start = System.currentTimeMillis();
String s = "";
for(int i = 0; i < 10000; ++i){
s += i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);
start = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer("");
for(int i = 0; i < 10000; ++i){
sbf.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);
start = System.currentTimeMillis();
StringBuilder sbd = new StringBuilder();
for(int i = 0; i < 10000; ++i){
sbd.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);
}
可以看待在对String类进行修改时,效率是非常低的,因此:尽量避免对String的直接需要.如果要修改建议尽量使用StringBuffer和StringBuilder
3.StringBuilder和StringBuffer
3.1StringBuilder的介绍
由于String的不可更改特性,为了方便字符串的修改,java中又提供StringBuilder和StringBuffer类,这两个类大部分功能是相同的,这里介绍StringBuilder常用的一些方法.
方法一: StringBuff append(String str) 在尾部追加,相当于String的+=,
可以加:boolean,char,char[],double,float,int,long,Object,String,StringBuff的变量
方法二:char charAt(int index) 获取index位置的字符
方法三:int length() 获取字符串的长度
方法四:int capacity() 获取底层保存字符串空间总的大小
方法五:void ensureCapacity(int mininmumCapacity) 扩容
方法六:void setCharAt(int index,char ch) 将index位置的字符设置为ch
方法七:int indexOf(String str) 返回str第一次出现的位置
方法八:int indexOf(String str,int fromIndex) 从fromIndex位置开始查找str第一次出现的位置
方法九: int lastIndexOf(String str) 返回最后一次出现str的位置
方法十: int lastIndexOf(String str,int fromIndex) 从fromIndex位置开始找str最后一次出现的位置
方法十一: StringBuff insert(int offset,String str) 在offset位置插入:八种基类类型&String类型 &Object类型数据
方法十二:StringBuffer deleteCharAt(int index) 删除index位置字符
方法十三:StringBuffer replace(int start,int end,String str) 删除[start,end]区间内的字符
方法十四:StringBuffer replace(int start,int end,String str) 将[start,end) 位置的字符替换为str
方法十五:String substring(int start) 从start开始一直到末尾的字符以Sring的方式返回
方法十六:String substring(int start,int end) 将[start,end)范围内的字符以String的方式返回
方法十七:StringBuffer reverse() 反转字符串
方法十八:String toString() 将所有字符按照String的方式返回
public static void main(String[] args({
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
//追加:即尾插-->字符串,整形数字
sb1.append(' '); // hello
sb1.append("world"); // hello world
sb1.append(123); // hello world123
System.out.println(sb1); // hello world123
System.out.println(sb1 == sb2); // true
System.out.println(sb1.charAt(0)); // 获取0号位上的字符 h
System.out.println(sb1.length()); // 获取字符串的有效长度14
System.out.println(sb1.capacity()); // 获取底层数组的总大小
sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123
sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123
System.out.println(sb1);
System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置
System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置
sb1.deleteCharAt(0); // 删除首字符
sb1.delete(0,5); // 删除[0, 5)范围内的字符
String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回
System.out.println(str);
sb1.reverse(); // 字符串逆转
str = sb1.toString(); // 将StringBuffer以String的方式返回
System.out.println(str);
}
class Solution {
public int firstUniqChar(String s) {
int[] count = new int[256];
// 统计每个字符出现的次数
for(int i = 0; i < s.length(); ++i){
count[s.charAt(i)]++;
}
从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,
而StringBuilder的内容可以修改,频繁修改字符串的情况考虑使用StringBuilder.
注意:String和StringBuilder类不能直接转换,如果要想互相转换,可以采用如下原则:
1.String变为Stringbuilder:利用StringBuilder的构造方法或append()方法
2.StringBuilder变为String:调用toString()方法
3.2面试题:
1.String,StringBuffer,StringBuilder的区别
·String 的内容不可修改,StringBuffer与StringBuilder的内容可以修改
·Stringbuffer与StringBuilder大部分功能是相似的
·StringBuffer采用同步处理,属于线程安全操作;而StringBuilder为采用同步处理,属于线程不安全操作
4.String类oj
1.第一个只出现一次的字符
class Solution {
public int firstUniqChar(String s){
int[] count = new int[256];
//统计每个字符出现的次数
for(int i= 0;i<s.length();++i){
count[s.charAt(i)]++;
}
//找第一个只出现一次的字符
for(int i=0;i<s.length();++i){
if(coutn[s.charAt(i)]){
return i;
}
}
return -1;
}
}
2.最后一个单词的长度
import java.util.Scanner;
public class Main{
public static void main(String[] args){
//循环输入
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
//获取一行单词
String s = sc.nextLine();
//1.找到最后一个空格
//2.获取最后一个单词;从最后一个空格+1的位置开始,一直截取到末尾
//3.打印最后一个单词长度
int len = s.substring(s.lastIndexOf('')+1,s.length().length());
}
sc.close();
}
}