string类及其方法
前言
我们首先了解一下JVM内存结构图
一、.String类
-
概念:String:字符串,使用一对""引起来表示。
-
定义格式:
方式一:通过new + 构造器的方式
例如:String str = new String(“abc”);
面试题:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
方式二:采用字面量直接赋值的方式
例如:String str = “abc”;
- 特点:String声明为final的,不可被继承.字符串是一个常量,一旦被创建,不可改变,指的是字符串的内容不可改变,因为它是在方法区的字符串池分配地址,但可以改变指向
例如:
String s=“hello”;
s=“abc”;
System.out.println(s);
输出的就是abc,并不是说hello被改变了,只是指向变成了abc
注意:
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中
举例说明字符串问题:
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false
final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";//因为s4被final修饰所以s5可看成存在与常量池中
System.out.println(s1 == s5);//true
}
@Test
public void test3(){
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
}
- String实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小 - String内部定义了final char[] value用于存储字符串数据
- String:代表不可变的字符序列。简称:不可变性。
体现:
当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋 值。
当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
- 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
- 字符串常量池中是不会存储相同内容的字符串的。
- 常用方法:
方法 | 解释 |
---|---|
length() | 返回字符串的长度 |
char charAt(int index) | 返回某索引处的字符 |
boolean isEmpty() | 判断是否是空字符串 |
String toLowerCase() | 使用默认语言环境,将 String 中的所有字符转换为小写 |
String toUpperCase(): | 使用默认语言环境,将 String 中的所有字符转换为大写 |
String trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
boolean equals(Object obj) | 比较字符串的内容是否相同 |
boolean equalsIgnoreCase(String anotherString) | 与equals方法类似,忽略大小写 |
String concat(String str) | 将指定字符串连接到此字符串的结尾。 等价于用“+” |
int compareTo(String anotherString) | 比较两个字符串的大小 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串 |
String substring(int beginIndex, int endIndex) | 返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串 |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出现处的索引 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右边出现处的索引 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 |
注:indexOf和lastIndexOf方法如果未找到都是返回-1
其他方法:
方法 | 解释 |
---|---|
boolean endsWith(String suffix) | 测试此字符串是否以指定的后缀结束 |
boolean startsWith(String prefix) | 测试此字符串是否以指定的前缀开始 |
boolean startsWith(String prefix, int toffset) | 测试此字符串从指定索引开始的子字符串是否以指定前缀开始 |
boolean contains(CharSequence s) | 当且仅当此字符串包含指定的 char 值序列时,返回 true |
用于替换的方法 | |
String replace(char oldChar, char newChar) | 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 |
String replace(CharSequence target, CharSequence replacement) | 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 |
String replaceAll(String regex, String replacement) | 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串 |
String replaceFirst(String regex, String replacement) | 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串 |
用于匹配的方法 | |
boolean matches(String regex) | 告知此字符串是否匹配给定的正则表达式 |
用于切片的方法 | |
String[] split(String regex) | 根据给定正则表达式的匹配拆分此字符串。 |
String[] split(String regex, int limit) | 根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中 |
1.构造方法
public String(byte[] bytes):把字节数组转换成字符串
public String(byte[] bytes,int index,int length):把字节数组从下标index开始到length个元素转换成字符串
public String(char[] chars):把字符数组转换成字符串
public String(char[] chars,int index,int count):把字符数组一部分转换成字符串
演示:
package org.westos.test;
public class Test2 {
public static void main(String[] args) {
//定义一个字节数组
byte[] bytes = {97,98,99,100};
//把字节数组转换成字符串
String s = new String(bytes);
System.out.println(s.toString());
//把字节数组从指定下标开始转换一定长度的元素为字符串
String s1 = new String(bytes,1,3);
System.out.println(s1);
System.out.println("----------------");
//定义一个字符数组
char[] chars = {65,66,67,68,69};
//把字符数组转换成字符串
String str = new String(chars);
System.out.println(str);
//把字符数组从指定下标开始转换一定长度的元素为字符串
String str2 = new String(chars,2,3);
System.out.println(str2);
}
}
运行结果:
这里在输出时自动将数字根据ASCII码表转换成单个字符,但不影响方法的使用
String类重写了toString方法,打印输出的是字符串内容
2.判断功能
public boolean equals(Object obj):比较两个字符串的内容是否相等,区分大小写
public boolean equalsIgnoreCase(String str):比较两个字符串的内容是否相等,不区分大小写
public boolean contains(String str):判断字符串中是否包含传递进来的字符串
public boolean startsWith(String str):判断字符串是否以传递进来的字符串开头
public boolean endsWith(String str):判断字符串是否以传递进来的字符串结尾
public boolean isEmpty():判断字符串是否为空串
演示:
package org.westos.test;
public class Test2 {
public static void main(String[] args) {
//比较两个字符串的内容是否一样,区分大小写
boolean b = "aaa".equals("aaa");
System.out.println(b);//true
boolean b1 = "aaa".equals("AAA");
System.out.println(b1);//false
//比较两个字符串的内容是否一样,不区分大小写
boolean b2 = "qqq".equalsIgnoreCase("qqq");
System.out.println(b2);//true
boolean b3 = "qqq".equalsIgnoreCase("QQQ");
System.out.println(b3);//true
//判断字符串中是否包含传递进来的字符串
boolean b4 = "zxcv".contains("xc");
System.out.println(b4);//true
//判断字符串中是否以传进来的字符开头
boolean b5 = "asdf".startsWith("as");
System.out.println(b5);//true
//判断字符串中是否以传进来的字符结尾
boolean b6 = "qwer".endsWith("r");
System.out.println(b6);//true
//判断字符是否是空串
boolean b7 = "rty".isEmpty();
System.out.println(b7);//false
}
}
运行结果:
String类重写了equals方法,比较的是两个字符串的内容是否一样
String类重写了equals方法,比较的是两个字符串的内容是否一样
3.获取功能
public int length():获取字符串长度
public char charAt(int index):获取指定索引位置的字符
public int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引
public int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引
public int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引
public int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引
public String substring(int start):从指定位置开始截取字符串,一直到末尾
public String substring(int start,int end):从指定位置开始到指定位置结束截取字符串
演示:
package org.westos.test;
public class Test2 {
public static void main(String[] args) {
//定义一个字符串
String str = "helloworld";
//获取字符串长度
int length = str.length();
System.out.println(length);
//获取指定索引位置的字符
char ch = str.charAt(2);
System.out.println(ch);//l
//获取指定字符第一次出现的索引值
int index = str.indexOf('w');
System.out.println(index);//5
//获取指定字符从指定位置后第一次出现的索引值
int index2 = str.indexOf('l',4);
System.out.println(index2);//8
//获取指定字符串第一次出现的索引值
//这里返回的索引值是指定字符串的第一个字符的索引值
int index3 = str.indexOf("owo");
System.out.println(index3);//4
//获取指定字符串从指定位置后第一次出现的索引值
int index4 = str.indexOf("l",4);
System.out.println(index4);//8
//顺带一提,之前的indexOf方法都是从前往后获取
//另外一种就是从后往前获取,就是lastindexOf方法,用法跟indexOf是一样的
//以获取指定字符第一次出现的索引值为例
//用lastindexOf方法就是获取从后到前第一次出现指定字符的索引值
int index5 = str.lastIndexOf('o');
System.out.println(index5);//6
//从指定位置开始截取字符串,一直到末尾
String s = str.substring(2);
System.out.println(s);//lloworld
//从指定位置开始到指定位置结束截取字符串
//这里注意,截取的部分含头不含尾,也就是说实际截取的是索引值2-5的字符
String s1 = str.substring(2,6);
System.out.println(s1);//llow
}
}
运行结果
4.转换功能
public byte[] getBytes():把字符串转换成字节数组
public char[] tocharArray():把字符串转换成字符数组
public static String valueOf(char[] ch):把字符数组转换成字符串
public static String valueOf(int i):把int类型的数据转换成字符串
public String toLowerCase():把字符串转换成小写
public String toUpperCase():把字符串转成大写
public String concat(String str):拼接字符串
演示:
package org.westos.test;
public class Test2 {
public static void main(String[] args) {
//定义一个字符串
String str = "helloworld";
//字符串转成字节数组
byte[] bytes = str.getBytes();
//遍历输出数组元素
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytes[i]+" ");
}
System.out.println();
//字符串转成字符数组
char[] chars = str.toCharArray();
//遍历输入字符数组
for (int i = 0; i < chars.length; i++) {
System.out.print(chars[i]+" ");
}
System.out.println();
//字符数组转成字符串
//定义一个字符数组
char[] ch = {'a','b','c'};
String s = String.valueOf(ch);
System.out.println(s);
//int类型的数据转成字符串
//valueOf方法可以将任意类型的数据转换成字符串
int i = 100;
String s1 = String.valueOf(i);
System.out.println(s1);
//把字符串转成大写
String s2 = str.toUpperCase();
System.out.println(s2);
//把字符串转成小写
String s3 = s2.toLowerCase();
System.out.println(s3);
//拼接字符串
String s4 = str.concat("abc");
System.out.println(s4);
}
}
运行结果:
5.其他功能
public String replace(char old,char new):用new字符替换old字符
public String replace(String old,String new):用new字符串替换old字符串
public String trim():去除两端空格
public int compareTo(String str):对照ASCII码表,从第一个字母进行减法运算,返回运算结果,区分大小写
public int compaerToIgnoreCase(String str):对照ASCII码表,从第一个字母进行减法运算,返回运算结果,不区分大小写
演示:
package org.westos.test;
public class Test2 {
public static void main(String[] args) {
//定义一个字符串
String str = " helloworld ";
//替换指定字符
String s = str.replace('l','q');
System.out.println(s);
//替换指定字符串
String s1 = str.replace("owo","zzz");
System.out.println(s1);
//去除两端空格
String s2 = str.trim();
System.out.println(s2);
//按字典顺序比较两个字符串
int result = str.compareTo(" helloworld ");
//减法运算后结果是0,表明两个字符串内容一样
System.out.println(result);
//按字典顺序比较两个字符串,忽略大小写
String s3 = str.toUpperCase();
int result2 = s3.compareToIgnoreCase(" helloworld ");
System.out.println(result2);
}
}
运行结果:
二、StringBuffer类和StringBuilder类
这两个类的很多方法与String的一样。并且这三个底层都使用char[]存储。
与String不同的是这两个类代表可变的字符序列。而String具有不变性。
其中StringBuffer是线程安全的,但效率低;
而StringBuilder(jdk5.0新增的)是线程不安全的,但效率高;
StringBuffer的常用方法:
方法 | 解释 |
---|---|
append(xxx) | 提供了很多的append()方法,用于进行字符串拼接 |
delete(int start,int end) | 删除指定位置的内容 |
replace(int start, int end, String str) | 把[start,end)位置替换为str |
insert(int offset, xxx) | 在指定位置插入xxx |
reverse() | 把当前字符序列逆转 |
indexOf(String str) | 返回指定字符串在此字符串中第一次出现的索引 |
substring(int start,int end) | 返回一个从stsrt开始到end索引结束的左闭右开区间的字符串 |
length() | 返回指定字符串长度 |
charAt(int n ) | 返回某索引处的字符 |
setCharAt(int n ,char ch) | 将字符串指定位置的字符替换为目标字符(将n处字符更换为 ch) |
具体如下:
总结:
增:append(xxx)
删:delete(int start,int end)
改:setCharAt(int n ,char ch) / replace(int start, int end, String str)
查:charAt(int n )
插:insert(int offset, xxx)
长度:length();
*遍历:for() + charAt() / toString()
String、StringBuffer、StringBuilder三者的异同
- String:不可变的字符序列;底层使用char[]存储
- StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
- StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储
- 对比String、StringBuffer、StringBuilder三者的效率:
从高到低排列:StringBuilder > StringBuffer > String
在开发中尽量使用StringBuffer
String类型的字符串与 StringBuffer、StringBuilder类的字符串之间的相互转换可通过使用对方的构造器就行。或 StringBuffer、StringBuilder可使用.toString方法转为String。
@Test
public void test1(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0,'m');
System.out.println(sb1);
StringBuffer sb2 = new StringBuffer();
System.out.println(sb2.length());//0
StringBuilder sb3=new StringBuilder("world");
String str=new String();
str=sb3.toString();
System.out.println(str);
}
运行结果:
mbc
0
world
三、Date类
1.java.util.Date类
表示特定的瞬间,精确到毫秒
- 两个构造器的使用
>构造器一:Date():创建一个对应当前时间的Date对象
>构造器二:创建指定毫秒数的Date对象 - 常用方法
(1)getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象
表示的毫秒数。
(2)toString():把此 Date 对象转换为以下形式的 String: dow mon dd
hh:mm:ss zzz yyyy 其中: dow 是一周中的星期几 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。
其它很多方法都过时了
@Test
public void test2(){
//构造器一:Date():创建一个对应当前时间的Date对象
Date date1 = new Date();
System.out.println(date1.toString());//Sat Feb 16 16:35:31 GMT+08:00 2019
System.out.println(date1.getTime());//1550306204104
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(155030620410L);//Sat Nov 30 16:03:40 CST 1974
System.out.println(date2.toString());
}
2. java.text.SimpleDateFormat类
-
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
-
SimpleDateFormat() :默认的模式和语言环境创建对象
-
public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:
public String format(Date date):方法格式化时间对象date
解析: -
public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
具体字母用途
举例说明:
@Test
public void test(){
Date date = new Date(); // 产生一个Date实例
// 产生一个formater格式化的实例
SimpleDateFormat formater = new SimpleDateFormat();
System.out.println(formater.format(date));// 打印输出默认的格式
System.out.println("******************");
//设置日期输出格式
SimpleDateFormat formater1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat formater2 = new SimpleDateFormat("yyyy年MM月dd日 E HH:mm:ss");
//输出当前的日期
System.out.println(formater1.format(date));
System.out.println(formater2.format(date));
System.out.println("************");
//指定时间
String str="2018-09-20";
try {
//利用parse将解析给定文本,以生成一个日期。
Date date1 = formater1.parse(str);
//利用getTime获取返回自 1970 年 1 月 1 日 00:00:00 GMT 以来到指定时间的的毫秒数。
System.out.println(date1.getTime());
//返回默认格式
System.out.println(date1.toString());
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("*********************");
try {
// 实例化一个指定的格式对象
Date date2 = formater2.parse("2018年09月20日 星期四 08:08:08");
// 将指定的日期解析后格式化按指定的格式输出
System.out.println(date2.toString());
//利用getTime获取返回自 1970 年 1 月 1 日 00:00:00 GMT 以来到指定时间的的毫秒数。
System.out.println(date2.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
}
}
五、比较器:Comparable与Comparator
1.Comparable
Comparable接口的使用举例: 自然排序
- 像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
- 像String、包装类重写compareTo()方法以后,进行了从小到大的排列
- 重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
举例:
@Test
public void test1(){
String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
//
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
- 对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。 在compareTo(obj)方法中指明如何排序
举例说明:
Goods类实现Comparable接口
public class Goods implements Comparable{
private String name;
private double price;
public Goods() {
}
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
//指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序
@Override
public int compareTo(Object o) {
// System.out.println("**************");
if(o instanceof Goods){
Goods goods = (Goods)o;
//方式一:
if(this.price > goods.price){
return 1;
}else if(this.price < goods.price){
return -1;
}else{
// return 0;
return -this.name.compareTo(goods.name);
}
//方式二:
// return Double.compare(this.price,goods.price);
}
// return 0;
throw new RuntimeException("传入的数据类型不一致!");
}
}
具体:
@Test
public void test2(){
Goods[] arr = new Goods[5];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
结果:
[Goods{name='xiaomiMouse', price=12.0}, Goods{name='lenovoMouse', price=34.0}, Goods{name='microsoftMouse', price=43.0}, Goods{name='dellMouse', price=43.0}, Goods{name='huaweiMouse', price=65.0}]
2.Comparator
Comparator接口的使用:定制排序
- 背景:
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,
那么可以考虑使用 Comparator 的对象来排序 - 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;
如果返回0,表示相等;
返回负整数,表示o1小于o2。
举例:
@Test
public void test3(){
String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
Arrays.sort(arr,new Comparator(){
//按照字符串从大到小的顺序排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
//重写之后从大到小排序
return -s1.compareTo(s2);
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}
运行结果:
[MM, KK, JJ, GG, DD, CC, AA]
Comparable接口与Comparator的使用的对比:
- Comparable接口的方式一旦一定,保证Comparable接口实现类的对象在任何位置都可以比较大小。
- Comparator接口属于临时性的比较。