Java SE - String自定义类型
目录
- 1.String的基本介绍
- 1.1 String的基本使用
- 1.2 字符串常量池
- 1.3 字符串常量不可修改的原因
- 2.String类型的搜寻方法
- 2.1 charAt()
- 2.2 indexOf()方法
- 2.3 lastIndexOf()方法
- 3. 字符串的转换
- 3.1 数值转换为字符串
- 3.2 字符串转换为数值
- 3.3 转换大小写
- 3.4 字符串的替换
- 4. 字符串的截取
- 5. intern()方法
- 6. split方法
- 7.StringBuffer和StringBuilder
1.String的基本介绍
String在Java中是一种引用数据类型,可定义与操作字符串,String这个类中存放多种方法,具体介绍可参考以下链接:String方法介绍
1.1 String的基本使用
String类型的使用与其它类型类似,都可以创建变量和初始化变量值,以下是几种常见的初始化赋值。
public class Main{public static void main(String[] args) {//1.直接赋值字符串常量String string = "abcdef";//2.通过String()方法新创建一个字符串对象后赋值String s = new String("abc");//3.创建数组,将数组通过String()方法转换为字符串char[] chars = new char[]{'a','b','c','d'};String s1 = new String(chars);//输出System.out.println("string = " + string);System.out.println("s = " + s);System.out.println("s1 = " + s1);}
}
1.2 字符串常量池
字符串常量池主要用于存放字符串常量,字符串常量是不可被修改的,字符串常量池是存放于堆区上的一块空间,在不同JDK中大小不一致,具体如下:
注意:字符串常量和new关键字创建的字符串虽然都存放在堆区,但是字符串常量对象的引用是存放于常量池中,而new关键字开辟的是在堆上的其它空间。
public class Main{public static void main(String[] args) {String s1 = "abc";String s2 = new String("ABC");}
1.3 字符串常量不可修改的原因
打开JAVA中String.java的文件,可以找到String是被public final修饰的,但是被final修饰的只能说明String这个类是不可继承的,与不可被修改并没有多大联系。
在String.java文件中还有一个被private final修饰的value数组,该数组用于存放字符串的,这是字符串常量不可被修改的真正原因,因为String类型定义的字符串创建后会将字符串存放于value数组中,然后将字符串常量池指向对象的地址赋值给String类型的引用,使用该引用只能访问字符串的数据,但是要修改字符串必须通过value数组,而value数组是被private修饰的,只能在当前类中使用,所以使用引用并不能修改到字符串常量的值,自然字符串常量就不可被修改。
如上:假设创建一个String 类型的引用s,将字符串常量池引用赋给s引用,”abc"在常量池不存在,会先在堆内存创建一个String对象,此对象中包含value数组,该数组是为了存放“abc"的内容的,使用s这个引用可以找到字符串常量池中引用指向的对象,而value数组是被private修饰的,在不同类中是不可访问到value数组的内容的,但是程序运行发生了运行时绑定,引用指向的就是value数组指向的内容,可以通过引用访问到常量字符串,而在编译时value数组本身不可被其它类访问到,就不可修改到常量字符串的内容。
2.String类型的搜寻方法
2.1 charAt()
charAt()方法是查找对应下标元素,参数类型是int,返回类型为char;
public class Main{public static void main(String[] args) {String s = "abcdefg";//charAt()找到当前下标的元素,与数组通过下标访问元素类似System.out.println(s.charAt(0));//找到0下标的字符,返回类型是char//找到字符‘a’;}
2.2 indexOf()方法
index()是通过索引找到第一次参数出现的位置,index()方法有几种重载的方法,第一种的是查找指定字符第一次出现的位置。参数类型是char,返回值类型是int,返回的是第一次出现的下标,如果不存在就返回-1,默认从0下标开始找。
public class Main{public static void main(String[] args) {String s = "abcdefg";//找到字符‘a’;找到引用指向对象第一次出现字符‘a'的下标:0System.out.println(s.indexOf('a'));//找到了:0System.out.println(s.indexOf('A'));//找不到:-1}
其它几种重载的方法类似,第一个参数是指定查找的元素或字符串,第二个参数是指定开始查找的位置。
public class Main{public static void main(String[] args) {String s = "abcdefg";System.out.println(s.indexOf('c',2));//返回2System.out.println(s.indexOf("abc"));//查找”abc"字符串,默认0下标查找,返回0System.out.println(s.indexOf("fg",3));//查找“fg",从3下标查找,返回5}
}
2.3 lastIndexOf()方法
lastIndexOf()方法与indexOf方法是类似的,只是lastIndexOf方法是默认从后往前查找,返回的也是第一次出现元素或者指定字符串首次出现的下标。
public class Main{public static void main(String[] args) {String s = "abcdefg";System.out.println(s.lastIndexOf('a'));//找到了:0System.out.println(s.lastIndexOf('A'));//找不到:-1System.out.println(s.lastIndexOf('c',2));//返回2System.out.println(s.lastIndexOf("abc"));//查找”abc"字符串,默认末尾下标查找,返回0System.out.println(s.lastIndexOf("fg",3));//查找“fg",从3下标查找,找不到,返回-1}
}
3. 字符串的转换
3.1 数值转换为字符串
使用String.valueOf()方法可以将整型数字或者浮点数转换为字符串,因为valueOf方法被static修饰,属于类方法,可以直接通过String(类名)+ ‘.’ (点) + 方法的形式调用,例如:将数字1234和3.14转换为字符串“1234”和"3.14".
public class Main{public static void main(String[] args) {int data1 = 1234;double data2 = 3.14;//转换String s1 = String.valueOf(data1);//"1234"String s2 = String.valueOf(data2);//"3.14"//输出System.out.println("s1 = " + s1);System.out.println("s2 = " + s2);}
3.2 字符串转换为数值
使用parseInt()方法或parseDouble()方法将字符串转变为对应的数值,返回类型为取决于调用的类型。
public class Main{public static void main(String[] args) {String str1 = "1234";String str2 = "3.14";//转换int data1 = Integer.parseInt(str1);//"1234" - > 1234double data2 = Double.parseDouble(str2);//"3.14" -> 3.14//输出System.out.println("data1 = " + data1);System.out.println("data2 = " + data2);}
}
3.3 转换大小写
使用toUnpperCase()方法可以将字符串中小写的字符转换为大写的字符,使用toLowerCase()方法可以将字符串中大写的字符转换为小写的字符,两者的返回类型都是String类型的引用。
public class Main{public static void main(String[] args) {String s1 = "abcdefg";String s2 = "ABCDEFG";//转换后输出System.out.println("s1 = " + s1.toUpperCase());//"ABCDEF"System.out.println("s2 = " + s2.toLowerCase());//"abcdef"}
3.4 字符串的替换
字符串的替换可使用replace()方法,参数为字符参数时,第一个参数内容为字符串中需要被替换的字符,第二个参数是指定替换的字符,参数为两个字符串时,第一个参数是字符串中的子串,第二个参数是指定替换的字符串;也可以使用replaceAll()方法,第一个参数是字符串中的子字符串,第二个参数替换的字符串。
public class Main{public static void main(String[] args) {String s = "abccba";String s1 = s.replace('a','A');String s2 = s.replace("abc","cba");String s3 = s.replaceAll("abc","ABC");System.out.println("s1 = " + s1);System.out.println("s2 = " + s2);System.out.println("s3 = " + s3);}
}
4. 字符串的截取
字符串的截取可以使用subString()方法,提供两种截取方式,第一种是指定下标位置开始截取,第二种是从指定的区间截取,默认是左闭右开。
public class Main{public static void main(String[] args) {String s = "See you again!";//截取//指定位置开始截取String s1 = s.substring(8);//again!//指定区间截取String s2 = s.substring(0,3);//左闭右开【0,2):See//输出System.out.println("s1 = " + s1);System.out.println("s2 = " + s2);}
5. intern()方法
intern()方法是将new String()创建的字符串转换为字符串常量,即将new String()创建的对象引用存放在字符串常量池中。
public class Main{public static void main(String[] args) {String s = new String("abcd");//使用intern方法String s1 = s.intern();//在字符串常量池中存储s引用//此时“abcd"是字符串常量String s2 = "abcd";System.out.println(s2 == s1);//ture}
如上图所示,new String(“abcd”)会在堆区上创建一个对象,对象中value数组存放的(或者是value这个引用指向的)内容是”abcd",此时在字符串常量池中不会存放s这个引用,此时的字符串还不是字符串常量,调用intern()方法会将value数组的内容拷贝一份,然后在堆区上重新创建一个String类型的对象,将拷贝的数组内容存放于新创建的value数组中,创建好对象后会返回一个String类型的引用,这个引用指向新开辟的String对象,同时也将这个引用存放在字符串常量池中,当重新创建String类型的引用s2时,此时字符串常量池已经存放的引用指向的对象的value内容就是“abcd",会将字符串常量池中存放的引用赋值给s2,所以s1 == s2 为true。
6. split方法
split()方法用于对字符串的分割,参数为指定的字符,例如:将字符串”I am a humorous person."按照空格分割,每一次分割都会返回String类型的引用,所以使用split方法可以使用String类型的数组接收返回值。
public class Main{public static void main(String[] args) {String s = "I am a humorous person.";String[] strings = s.split(" ");//按照空格分割//for-each循环遍历数组for(String tem : strings){//输出System.out.print(tem + " ");}}
}
例子:将IP地址按照“."分割,例如百度ip地址:119.75.217.109。
由于”.“是一个特殊的字符,按照“.“分割时需要使用’\.'(两个斜杠点,此处只能显示一个),第一个表示转意字符,转换原有含义,第二个表示将第一个斜杠转意,此时默认的就是“\.”,传递给正则表达式就代表”.”,常见的需要转意字符还有:“+” ,“*”,“|”,”\“(表示一个斜杠)。具体正则表达式介绍可参考以下网站:正则表达式—菜鸟教程
public class Main{public static void main(String[] args) {String s = "119.75.217.109";String[] strings = s.split("\\.");//按照'.'分割System.out.print("IP: ");for (int i = 0; i < strings.length; i++) {System.out.print(strings[i]);if(!(i == strings.length - 1))System.out.print(".");}}
}
7.StringBuffer和StringBuilder
StringBuffer和StringBuilder此处介绍的是在拼接中,不推荐使用+的方式,因为效率比较低,推荐使用的是append方法。
public class Main{public static void main(String[] args) {//拼接的使用StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < 10; i++) {stringBuffer.append(i);//将0 - 9拼接}System.out.println(stringBuffer);StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i < 10; i++) {stringBuilder.append(i);//将0 -9 拼接}System.out.println(stringBuilder);}
}
对比使用String类型的拼接的时间,此时使用
public class Main{public static void main(String[] args) {//拼接的使用StringBuffer stringBuffer = new StringBuffer();long start1 = System.currentTimeMillis();//记录当前时间for (int i = 0; i < 1000; i++) {stringBuffer.append(i);//}long end1 = System.currentTimeMillis();//记录拼接完成时间System.out.println("time1 :" + (end1 - start1));StringBuilder stringBuilder = new StringBuilder();long start2 = System.currentTimeMillis();//记录开始拼接的起始时间for (int i = 0; i < 1000; i++) {stringBuilder.append(i);}long end2 = System.currentTimeMillis();//记录拼接完成后的时间System.out.println("time2 :" + (end2 - start2));//String类型的+拼接String s = "";long start3 = System.currentTimeMillis();//记录当前时间for (int i = 0; i < 1000; i++) {s = s + i;}long end3 = System.currentTimeMillis();//拼接完成后的时间System.out.println("time3 :" + (end3 - start3));}
}
可以观察到相差的时间是成倍数的,单位是毫秒,这是因为String类型的拼接实际上还是调用了StringBuffer或者StringBuilder的append方法,而且需要重新创建对象,会造成内存碎片化的增多,内存的使用效率偏低,因此在使用拼接时,推荐使用append方法。
关于StringBuffer或者StringBuilder的其它内容可以参考以下链接:StringBuffer官网介绍 和StringBuilder官网介绍