前言
大家好呀,本期将要带大家认识一下Java中的String类,本期注意带大家认识一些String类常用方法,和区分StringBuffer和StringBuilder感谢大家收看
一,String对象构造方法与原理
String类为我们提供了非常多的重载的构造方法让我们构造字符对象,感兴趣可以点开源码看看,下面介绍常用四种以及使用场景
1.常量池直接构造:最简便的构造方式,栈中创建的对象的引用指向常量池中的对象,如下图str
2.使用new构造:在堆区中开辟一片空间存放字符对象,如下图str1
3.字符数组构造:New的String对象传入一个字符数组构造字符对象,如下图str2
4.字节数组构造:利用字节数组构造,此时需注意字节数组中存放字母的ACCII码值,构造时需选择编码格式,一般使用UTF-8编码格式进行编码如下图str3
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String str="helloWorld";//直接构造
String str1=new String("helloWorld");//new出对象
char[] ch={'h','e','l','l','o','W','o','r','l','d'};
String str2=new String(ch);//字符数组构造
byte[] bytes = {104, 101, 108, 108, 111}; // 字节数组,对应ASCII "hello"
String str3 = new String(bytes, "UTF-8"); // 使用UTF-8编码构造字符串
System.out.println(str+"\n"+str1+"\n"+str2+"\n"+str3);
}
}
值得一提利用字符数组和字节数组有常见的构造方法
表示截取var1字数数组中从var2到var3的字符构造字符串,截取的区间左闭右闭,例如
二,String对象的不可变性
String对象一经创建,便不可更改,更改的话,只会在创建一个新的对象,把更改过后的内容放进去,这个就是String对象的不可变性,String的这个特性使的对String对象的操作相对低效,于是StringBuilder类就可以提高我们的效率。后面介绍StringBuilder类时会详细说明
三,String类中的常用方法
1,字符串转换
(1)大小写转换
java中使用toUpperCase和toLowercase对字符串进行大小写转换,注意这个方法不会改变原来字符串,而是返回一个新的字符串
public class Test1 {
public static void main(String[] args) {
String str="HELLO";
String str1=str.toLowerCase();
System.out.println(str1);
String str2="hello";
String str3=str2.toUpperCase();
System.out.println(str3);
}
}
(2)字符串和数值转换
Java中,如果想把一个子符转成数值需要用到它们对应类型的包装类,同样,把任意类型对象转成字符串需要用到String的valueOf方法,如下
public class Test1 {
public static void main(String[] args) {
String s="1234";
System.out.println(Integer.parseInt(s));
int i=1234;
System.out.println(String.valueOf(i));
}
}
(3)字符串转数组
字符串对象调用toCharArray方法,返回一个字符数组,可以得到字符串中每个字符,然后,我们可以遍历这个数组打印观察其中的字符
public class Test1 {
public static void main(String[] args) {
String str="hello";
char[] ch=str.toCharArray();
for (int i=0;i<ch.length;i++){
System.out.println(ch[i]);
}
}
}
(4)格式化
String类调用format方法,优点在于可以更方便地创建复杂的输出字符串,特别是在需要格式化输出的时候,学过C语言的小伙伴们应该不陌生,例如
public class Test1 {
public static void main(String[] args) {
String str="hello";
String str1="World";
int i=10;
System.out.println(String.format("%s %s %d", str, str1,i));
}
}
2,寻找字符
(1)寻找某个下表对应字符--charAt
String对象调用charAt(in i)方法,传入一个字符串对应字符的下标,返回对应下标的字符,源码如下
顺带一提如果字符由数字组成也返回一个数字字符
public class Test1 {
public static void main(String[] args) {
String str="hello";
String str1="World";
String str3="16774";
char ch=str3.charAt(1);
char ch1=str1.charAt(0);
System.out.println(ch);
System.out.println(ch1);
}
}
(2)寻找某个字符首次出现位置--indexOf
String对象调用Indexof方法传入一个字符,返回对应字符首次出现的下标值,它还可以在传入一个int值表示从这个int值对应的下表开始找对应字符,没找到返回-1。
public class Test1 {
public static void main(String[] args) {
String str="Hello World";
System.out.println(str.indexOf("l"));
System.out.println(str.indexOf("l",5));//只传入一个数,表示从5下标一直找到结尾
}
}
(3)从字符串末尾开始向前找字符--lastIndexof
与indexof用法类似,不过这次是从后向前找字符,没找到则返回-1
public class Test1 {
public static void main(String[] args) {
String str="Hello World";
System.out.println(str.lastIndexOf("l"));
System.out.println(str.lastIndexOf("l",5));//传入一个数,表示从5一直向前找
}
}
3,字符串比较
(1)==
实质上是比较字符串的地址,同一地址返回true否则返回false
public class Test1 {
public static void main(String[] args) {
String str="Hello";
String str1=new String("Hello");
String str2="Hello";
String str3=new String("Hello");
System.out.println(str==str1);//前面已经讲过字符串的构造,很明显地址不同
System.out.println(str==str2);//都在常量池中地址相同
System.out.println(str1==str3);//每次new都会在堆区开辟空间,二者地址不同
}
}
(2)equals
只比较字符串内容,与地址无关(String内部重写了这个方法)
public class Test1 {
public static void main(String[] args) {
String str = "Hello";
String str1 = new String("Hello");
String str2 = "Hello";
System.out.println(str.equals(str1));
System.out.println(str.equals(str2));
System.out.println(str1.equals(str2));
}
}
(3)compareTo
这部分内容我们在接口部分讲过,主要是我们重写Comparable接口中的compareTo方法来比较两个字符类型的大小。注意String类是重写了compareTo这个方法的,我们直接使用即可,它会根据比较字符的大小返回一个整型值,对这部分内容感兴趣的朋友们可以看看CSDN这篇文章,下面说明String对象如何调用这个方法
public class Test {
public static void main(String[] args) {
String s="hello";
String s1="world";
System.out.println(s.compareTo(s1));//s小于s1,返回一个小于0的数
System.out.println(s1.compareTo(s));//s1大于s,返回一个大于0的数
System.out.println(s.compareTo(s));//相同字符串返回0
}
}
4,字符串操作
(1)替换操作--replace
使用replace方法可以把字符串中特定的所有字符替换成指定字符
public class Test {
public static void main(String[] args) {
String s = "hello,world";
String s1 = s.replace("l", "s");
System.out.println(s+"\n"+s1);
}
}
当然,这个方法会返回一个新对象,不会对原来字符串做任何修改
(2)分裂操作--split
Java中有将字符串根据指定字符拆分成几个子字符串的方法
由源码可以看出,这个方法传入一个字符,返回一个String类型的数组,我们可以通过遍历得到这个数组每个元素
public class Test {
public static void main(String[] args) {
String s = "hello,world";
String[] str=s.split("l");
for (int i = 0; i <str.length; i++) {
System.out.println(str[i]);
}
}
}
当然也可以传入一个字符串
public class Test {
public static void main(String[] args) {
String s = "hello,world";
String[] str=s.split("ll");
for (int i = 0; i <str.length ; i++) {
System.out.println(str[i]);
}
}
}
当然,要是没有这个字符那么这个字符串就不会被分割
public class Test {
public static void main(String[] args) {
String s = "hello,world";
String[] str=s.split("k");
for (int i = 0; i <str.length ; i++) {
System.out.println(str[i]);
}
}
}
四,StringBuffer与StringBuilder应用与区分
StringBuffer与StringBuilder用法和功能都是类似的,区别就在于StringBuilder对字符串的操作都是在原字符之上修改,并不会创建新的对象,这就使得StringBuiler效率优于String类,举个例子,StringBuilder类有一个append的拼接字符串的方法,这个方法就会比String类通过+=拼接效率更高
import java.util.Timer;
public class Test {
public static void main(String[] args) {
String s = "hello";
StringBuilder s1 = new StringBuilder("hello");
Long time1=System.currentTimeMillis();
//记录当前时间
for (int i = 0; i <10000 ; i++) {
s+="i";
}
Long time2=System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
s1.append("i");
}
Long time3=System.currentTimeMillis();
System.out.println(time2-time1);
System.out.println(time3-time2);
}
}
另外,StringBuilder对象可以通过toString方法转化成String对象
public class Test1 {
public static void main(String[] args) {
StringBuilder s1 = new StringBuilder("hello");
String s=s1.toString();
}
}
StringBuffer类于他们只有一个区别,StringBuffer类的操作属于线程安全操作,它的大部分方法都加上了
synchronized关键字,如下
线程安全操作简单理解就是指在多线程情况下,这个方法会被执行完才会让出cpu资源,执行后面代码,这保证了代码逻辑的正确性,当然,与之相对效率差一点点,所以在单线程情况下还是常用另外两个方法。
本期博客就到到这里啦,记录个人学习欢迎大家指正错误哦,谢谢大家,我们下期见