作者:~小明学编程
文章专栏:JavaSE基础
格言:目之所及皆为回忆,心之所想皆为过往
目录
String、StringBuffer、StringBuilder的区别
字符,字节与字符串
字符与字符串
字符串内部包含一个字符数组,String 可以和 char[] 相互转换。
字符数组转字符串
利用String类的构造方法将字符数组转换为字符串:
public static void main(String[] args) {
char[] array = {'a','b','c'};
String str1 = new String(array);
System.out.println(str1);//abc
}
部分字符数组变为字符串
利用String类的构造方法将部分字符数组转换为字符串:
public static void main(String[] args) {
char[] array = {'a','b','c'};
String str2 = new String(array,1,2);
System.out.println(str2);
}
获取指定位置字符
从0开始获取字符串指定位置的字符:
public static void main(String[] args) {
String str1 = "hello world!";
char ch = str1.charAt(4);
System.out.println(ch);//打印o
}
字符串转字符数组
将字符串转换为字符数组:
public static void main(String[] args) {
String str = "abcdefg";
char[] arr = str.toCharArray();
System.out.println(Arrays.toString(arr));
}
判断字符串是否全为数字
我们现在利用前面刚学的这几个方法来写一个简单的判断一个字符串是否全部由数字组成的方法
public static boolean isNumberChar(String str) {
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if(ch<='9'&&ch>='0') {
continue;
} else {
return false;
}
}
return true;
}
public static boolean isNumberChar2(String str) {
char[] array = str.toCharArray();
for (int i = 0; i < str.length(); i++) {
if(array[i]<='9'&&array[i]>='0') {
continue;
} else {
return false;
}
}
return true;
}
public static void main(String[] args) {
String str = "1234567l";
System.out.println(isNumberChar2(str));
}
我们这里给了两种方法,第一种就是通过循环和charAt()方法获取到字符指定位置的字符将其转换为字符然后再进行判断。第二种就是将整体的字符串全部转换为字符数组然后遍历数组,一一判断。
字节与字符串
public static void main(String[] args) {
byte[] array = {97,98,99,100};
String str = new String(array);
System.out.println(str);//abcd
}
这里我们利用构造方法将byte类型的数组转换为字符串,转换的过程中是通过ASCII码表转换为字符最后合并为字符串。
public static void main(String[] args) {
byte[] array = {97,98,99,100};
String str = new String(array,1,3);
System.out.println(str);//bcd
}
这里同样支持从指定位置开始转换。
public static void main(String[] args) {
String str = "abcdef";
byte[] arr = str.getBytes();
System.out.println(Arrays.toString(arr));
}
//[97, 98, 99, 100, 101, 102]
利用getBytes()将字符串转换为字节数组。
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "小明";
byte[] arr = str.getBytes("utf-8");
System.out.println(Arrays.toString(arr));
}
上面我们加了个编码格式utf-8,表示我们用utf-8的格式进行编码并且并且转换为字节码。
//[-27, -80, -113, -26, -104, -114]
这里是我们的打印结果,当我们换了个编码格式的时候
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "小明";
byte[] arr = str.getBytes("GBK");
System.out.println(Arrays.toString(arr));
}
//[-48, -95, -61, -9]
当我们用GBK的编码格式(默认编码格式)进行编码并且转换为字节码的时候我们会发现结果是不一样的,同时也证明了在不同的编码格式下我们的中文字符所占的字节数是不一样的。
注意:
何时使用 byte[], 何时使用 char[] 呢?
byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合针对二进制数据来操作。
char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候。
回忆概念: 文本数据 vs 二进制数据
一个简单粗暴的区分方式就是用记事本打开能不能看懂里面的内容.
如果看的懂, 就是文本数据(例如 .java 文件), 如果看不懂, 就是二进制数据(例如 .class 文件)
字符串常见操作
字符串的比较
equals()方法
public static void main(String[] args) {
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equals(str2));//false
}
equals方法常被用来比较两个字符串的是否相等,相等返回true不相等就返回false。
在使用的时候需要注意:
public static void main(String[] args) {
String str1 = null;
String str2 = "Hello";
System.out.println(str1.equals(str2));
}
如果我们的str1是空指针的话则会报错,如果写成这样的话:
public static void main(String[] args) {
String str1 = null;
String str2 = "Hello";
System.out.println(str2.equals(str1));//false
}
就会输出false,根据我们的需要进行选择写法。
//equals方法的源码
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;
}
上面是equals方法的源码,这里简单给大家介绍一下。
if (this == anObject) {
return true;
}
首先的这一步是判断一下我们的地址是否一样,地址一样的话就直接返回true了,也就是对应我们下面这段代码。
public static void main(String[] args) {
String str1 = "hello";
String str2 = str1;
System.out.println(str2.equals(str1));//true
}
我们的str1和str2都是指向同一个地址的,所以两个字符串肯定是一致的。
if (anObject instanceof String)
这个if()语句的主要功能就是判断我们想要比较的str1是否是String类型的如:
public static void main(String[] args) {
int str1 = 10;
String str2 = "hello";
System.out.println(str2.equals(str1));//false
}
我们的str1是int类型的这就没必要在接着往下去进行了,直接返回false就完事了,否则的话再进入我们里面的循环逐一比较。
equalsIgnoreCase()
equalsIgnoreCase()和equals()的用法基本一样只不过equalsIgnoreCase()在比较字符串的时候是不考虑大小写的。
public static void main(String[] args) {
String str1 = "HELLO";
String str2 = "hello";
System.out.println(str2.equalsIgnoreCase(str1));//true
}
compareTo
这是一个字符串比大小的方法
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;
}
这里我们也是调出了它的源码,找出最短的,然后比较,返回的是不同字符的ASCII码的差值。
字符串的查找
contains()方法
public boolean contains(CharSequence s) {//源码
return indexOf(s.toString()) > -1;
}
该方法用于判断当前字符串中是否存在字符串s。
public static void main(String[] args) {
String str1 = "abababccba";
System.out.println(str1.contains("abc"));//true
}
indexOf()方法
public int indexOf(String str) {//源码
return indexOf(str, 0);
}
该方法返回我们要查找的子字符串的下标,当内容重复的时候会率先返回第一次搜索到的位置,找不到的话就返回-1。
public static void main(String[] args) {
String str1 = "abababccba";
System.out.println(str1.indexOf("abc"));//4
}
public int indexOf(String str, int fromIndex) {//源码
return indexOf(value, 0, value.length,
str.value, 0, str.value.length, fromIndex);
}
我们在此方法中多加了一个参数,fromIndex顾名思义就是从指定的位置开始查找。
public static void main(String[] args) {
String str1 = "abababccba";
System.out.println(str1.indexOf("ba",4));//8
}
lastIndexOf()方法
public int lastIndexOf(String str) {//源码
return lastIndexOf(str, value.length);
}
public static void main(String[] args) {
String str1 = "abababccba";
System.out.println(str1.lastIndexOf("ba"));//8
}
该方法也是返回我们所要查找的子字符串的下标,只不过是从后开始搜索的。
public static void main(String[] args) {
String str1 = "abababccba";
System.out.println(str1.lastIndexOf("ba",7));//3
}
同上后面加了个下标,从指定的位置开始搜索。
startsWith()方法
public boolean startsWith(String prefix) {//源码
return startsWith(prefix, 0);
}
public static void main(String[] args) {
String str1 = "hello world";
System.out.println(str1.startsWith("he"));//true
}
该方法用于判断字符串是否以指定的字符串开头。
public static void main(String[] args) {
String str1 = "hello world";
System.out.println(str1.startsWith("he",2));
}
该方法加了一个参数后就是从指定位置开始判断,字符串是否以子字符串开头的。
endsWith()方法
public boolean endsWith(String suffix) {//源码
return startsWith(suffix, value.length - suffix.value.length);
}
public static void main(String[] args) {
String str1 = "hello world";
System.out.println(str1.endsWith("world"));//true
}
该方法用于判断我们的字符串是否以指定的子字符串结尾。
字符串的替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
public static void main(String[] args) {
String str = "hello hello world!";
System.out.println(str.replaceAll("ll","aa"));//heaao heaao world!
}
该方法将原字符串里的所有"ll"都替换为"oo"。
public static void main(String[] args) {
String str = "hello hello world!";
System.out.println(str.replaceFirst("ll","aa"));//heaao hello world!
}
replaceFirst是将str字符串里的第一次出现的目标字符串替换为指定的字符串。
字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
public String[] split(String regex, int limit)
split()方法中有两个参数,一个是分割标识符,一个是划分最多字符串个数。
public static void main(String[] args) {
String str = "hello&&world&&Hi&&world";
String[] arr = str.split("&&");
for (String x:arr) {
System.out.println(x);
}
}
上述代码我们通过&&将字符串分割成了一个个的字符串。
public static void main(String[] args) {
String str = "hello&&world&&Hi&&world";
String[] arr = str.split("&&",2);
for (String x:arr) {
System.out.println(x);
}
}
分割成了两个字符串。
注意:
拆分IP地址
public static void main(String[] args) {
String ip = "158.198.2.3";
String[] arr = ip.split(".");
for (String x:arr
) {
System.out.println(x);
}
}
结果和我们想的并不一样,结果输出的是空。这又是什么原因呢?
通过源码我们了解到了我们传的是一个正则表达式,而点(.)是需要\去转义的,而\则又需要\再去转义的,所以我们最后将会写成
String[] arr = ip.split("\\.");
1. 字符"|","*","+"都得加上转义字符,前面加上"\".
2. 而如果是"",那么就得写成"\\".
3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符
public static void main(String[] args) {
String str = "hello&&world Hi&&world";
String[] arr = str.split("&&| ");
for (String x:arr) {
System.out.println(x);
}
}
多次拆分即把已经拆分的字符串再次进行拆分。
public static void main(String[] args) {
String ip = "158.198.2.3";
String[] arr = ip.split("\\.");
for (String x:arr) {
String[] ret = x.split("5|9");
for (String y:ret) {
System.out.println(y);
}
}
}
字符串的截取
substring()方法
substring()方法是我们常用的字符串截取的方法,该方法可以传一个参数,也可以传两个参数,当传一个参数的时候就是从指定的位置开始截取后面的字符串,传两个参数的时候就是,从指定位置开始截取,一直截取到指定下标的位置,这里采取的是常见的左开右闭。
public static void main(String[] args) {
String str = "abcdefghijklmn";
System.out.println(str.substring(3));
System.out.println(str.substring(3,5));
System.out.println(str.substring(0));
}
//defghijklmn
//de
//abcdefghijklmn
这里值得我们注意的一点就是,当我们只是传一个参数且是0的时候,我们截取的就是整个字符串,并且这时候返回的是原来的对象。
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
上面这段代码是substring()方法的返回值,可以看到当beginIndex==0的时候我们返回的是this。
其它操作方法
trim()方法:去掉字符串首尾的空格,保留中间的空格。
toUpperCase()方法:字符串转大写。
toLowerCase()方法:字符串转小写。
concat()方法:字符串的连接。
length()方法:计算字符串的长度。
isEmpty()方法:判断字符串是否为空。
public static void main(String[] args) {
String str1 = " hel lo ";
str1 = str1.trim();
String str2 = str1+"world";
System.out.println(str2);//hel loworld
System.out.println("_____________");
String str3 = "anjdADF78哈哈";
System.out.println(str3.toUpperCase());//ANJDADF78哈哈
System.out.println(str3.toLowerCase());//anjdadf78哈哈
System.out.println("_____________");
String str4 = "hello";
str4 = str4.concat("world");
System.out.println(str4);//helloworld
System.out.println(str4.length());//10
System.out.println("_____________");
String str5 = "";
System.out.println(str5.isEmpty());//true
}
StringBuffer 和 StringBuilder
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
public static void main(String[] args) {
StringBuffer str = new StringBuffer("hello ");
str.append("world");
System.out.println(str);
}
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法.
String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的情况考虑使用StingBuffer。
为了更好理解String和StringBuffer,我们来看这两个类的继承结构:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
可以发现两个类都是"CharSequence"接口的子类。这个接口描述的是一系列的字符集。所以字符串是字符集的子类,如果以后看见CharSequence,最简单的联想就是字符串。
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则。
1.String变为StringBuffer:利用StringBuffer的构造方法或append()方法。
2.StringBuffer变为String:调用toString()方法。
public static void main(String[] args) {
StringBuffer str = new StringBuffer("hello ");
str.append("world");
String str1 = str.toString();//StringBuffer转String
str = new StringBuffer(str1);//String转StringBuffer
System.out.println(str);
}
除了append()方法外,StringBuffer也有一些String类没有的方法
reverse()方法:反转字符串。
delete()方法:删除指定位置。
insert()方法:在指定位置插入数据。
public static void main(String[] args) {
StringBuffer str = new StringBuffer("Hello");
System.out.println(str.reverse());//反转字符串 olleH
System.out.println(str.delete(1,3));//删除指定位置 oeH
System.out.println(str.insert(1,"AAA"));//在指定位置插入数据 oAAAeH
}
String、StringBuffer、StringBuilder的区别
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
StringBuffer与StringBuilder大部分功能是相似的。
StringBuffer采用同步处理,属于线程安全操作,而StringBuilder未采用同步处理,属于线程不安全操作。