目录
1.String类介绍
1.C语言的时候学过字符和字符串,都是以字符数组和字符指针的方式储存的,例如
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};以'\0'作为字符串结束的标志
以上代码可以直接写成这样也是一样的结果:
不指定长度,直接初始化
char site[] = "RUNOOB";
Java的String类根据面向对象的思想来说是一个类,有自己的构造方法,成员变量,以及成员方法
储存时有以下方式:
String str = "huaweilin";//在常量池中寻找对象;把对象的地址值赋值给str
String str = new String("huaweilin");在堆上创建对象,str指向对象存储对象的地址值,value值为huaweilin;
char[] array = {'h','u','a','w','e','i','l','i','n'}//利用字符数组作为构造方法的参数,跟第二种方法差不多,也是需要在堆上创建对象
2.引用类型String
上面学会初始化String类,下面了解一个很重要的概念,就是字符串是怎么判断相等或者比较的
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
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
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
}
s1和s2和s3都是在堆上创建对象
结果s1的值不等于s2
s4赋值给s1反而两个相等
是因为String类的对象s1和s2和s3不是存储内容而是存储对象的地址值
而s4把他的地址值赋给了s1,所以两者相等,这里注意==比较的是两个变量储存的值是否相同
所以如果是要比较两个字符内容是否相同应该调用String类的equals()和compareTo()方法:
3.字符串的比较
一.boolean equals()方法
String str = new String("huaweilin");
String s1 = "huaweilin";
System.out.println(str.equals(s1));//true
虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
equals()都是逐个字符进行比较的,返回值为Boolean;源码如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
二.int compareTo()方法:
String s1 = new String("abc");
String s2 = new String("ac");
System.out,println(s1.compareTo(s2));/*逐个字符进行比较,返回他们字符的差值,比如第二位b!=c,所以就是b的ASCII码值减去c的ASCII码值等于-1*/
String s3 = new String("abc");
System.out,println(s1.compareTo(s3));//相同返回值为0
String s4 = new String("abcdef");/*返回-3,这种情况是如果前几个字符都比较相同,然后再进行下一个比较时超出了两个字符串的最小长度,就会返回两个字符串的差值*/
以上结果出现的原因由于compareTo()方法的源码:(源码需要自己调用方法时按住ctrl键点一下就会出现了)
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
有一个方法与compareTo类似,叫compareToIgnoreCase(String str)方法,他可以比较时忽略大小写,大写和小写就被当做相同,大小写默认为相同的字符
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.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
4.字符串的查找
一.获取字符串里的字符;char charAt(int index)
public static void main(String[] args){
String s = new String("11byte");
for(int i = 0,i < s.length(); i++){
char[] x = s.charAt(i);
}
二.根据下标找对应的字符或字符串,或者根据字符或者字符串找对应的下标
char charAt()方法 indexOf()方法 lastindexOf()方法
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";String底层是用数组来存储字符串的,所以下标需从0开始
System.out.println(s.charAt(3)); // 'b' 获取3下标的字符
System.out.println(s.indexOf('c')); // 6 获取第一次出现c的下标
System.out.println(s.indexOf('c', 10)); // 15 获取从10下标开始,第一次出现c的下标
System.out.println(s.indexOf("bbb")); // 3 获取第一次出现bbb字符串的下标
System.out.println(s.indexOf("bbb", 10)); // 12 获取从10下标开始,第一次出现bbb字符串的下标
System.out.println(s.lastIndexOf('c')); // 17 从后往前数,返回第一次出现c的下标
System.out.println(s.lastIndexOf('c', 10)); // 8 从下标10往前数,第一次出现c的下标
System.out.println(s.lastIndexOf("bbb")); // 12 后往前数,第一次出现字符串bbb的下标,
System.out.println(s.lastIndexOf("bbb", 10)); // 3 从下标10往前数,第一次出现bbb的下标
注意的是:
indexOf()和lastindexOf()对于获取字符串的位置都是以字符串的开头下标作为返回值,没有找到则返回-1
5.转化
1.数值和字符串转化
valueOf()方法,把数字转成字符串,String.valueOf(int i)源码如下:
String sw = String.valueOf(11);
System.out.println(sw);
用parseInt()方法,像Integer,Double要用他们的包装类调用此方法
int a = Integer.parseInt("12");
System.out.println(a);//12
double b = Double.parseDouble("11.77");
System.out.println(b);//11.77
用valueOf()转字符串为数字也可以,下面看看Integer.valueOf(int i)的源码:
本质上还是用的parseInt方法把字符串转化为了数字,上面的radix是进制的意思
6.字符串常量池
只要是双引号引起来的元素,都要放在常量池,且只有一份
当使用String s1 = "hello"的时候,现在常量池里找,找到了,就把该字符串的引用赋值给s1;
哈希桶存储了String对象的地址值,String对象里又存储着字符串的地址值,按照上面的图仔细感受下面代码的不同
public static void main(String[] args) {
String s1 = "hello";//1
String s2 = "hello";//2
String s3 = new String("hello);//3
当第1条语句执行时,会去找常量池中有没有"hello"这个字符串,如果有则把存储"hello"字符串哈希表里的地址赋给s1,没有则会把"hello"进入到常量池里;当第二条语句执行时,"hello"已经存在常量池里,则直接把引用赋值给s2,当第三条语句执行时,会创建一个新的对象,这时的引用跟前面的就不一样了,但他还是会去常量池寻找字符串,如果有则会把字符串的引用直接赋值给s3.
所以这里注意引用的不同:s1和s2都是直接在StringTable里找,找到了就把StringTable上的引用赋值给变量,没找到就把元素入常量池,在常量池构建一个哈希表
s3在new了对象之后在堆上开辟了一个新的空间,也是先去常量池找,如果找到相同的元素则把字符串的引用赋值给s3
7.StringBuilder和StringBuffer
StringBuilder和StringBuffer不是String,是单独出来的一个类,便于对字符串进行操作
方法如下:
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 delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
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);
}
从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可
以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法。
1. String、StringBuffer、StringBuilder的区别
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
StringBuffer与StringBuilder大部分功能是相似的
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
以下面为例介绍
String str = new String("ab"); // 会创建多少个对象
String str = new String("a") + new String("b"); // 会创建多少个对象
第一个创建对象ab,创建了一个对象
第二个创建了对象a和对象b以及StringBuilder类对象ab,一共创建了3个对象
字符串在拼接时会创建一个StrimgBuilder类的对象,最后再通过toString()方法转变成字符串.
8.字符串的不可变性
String是一种不可变对象,字符串的内容不可改变
源码中对于String类的描述:
String类无论在声明时直接引用,还是new一个对象,里面的字符实际都保存在内部维护的value字符数组中:final表明value中引用该数组的地址值不能被修改且只有一份,并且由于private,外部类无法获取value的值,但引用的数组里面的值是可以通过数组下标的方式改变的,比如说:
public class Example{ String str = new String("good"); char[ ] ch = { 'a' , 'b' , 'c' }; public static void main(String args[]){ Example ex = new Example();//给类创建对象,包含了类里面的属性 ex.change(ex.str,ex.ch);//给方法传参数 System.out.print(ex.str + " and "); System.out.print(ex.ch); } public void change(String str,char ch[ ]){ str = "test ok";//final修饰无法改变引用的值(无法改变value[]数组的地址值) ch[0] = 'g';//数组内部可利用数组下标进行修改 } }输出结果为good and gbc