十三、常用类(完结)
十三、常用类
13.1 包装类
13.1.1 包装类的分类
介绍:针对八种基本数据类型对应的引用类型
作用:可以调用包装类里面的方法
分类:
13.1.2 包装类的继承关系
- 学一个类首先要搞清楚类的继承关系
- Boolean 和 Character 父类一致
- 其他六种包装类父类一致
13.1.3 装箱(boxing)和拆箱(unboxing)
jdk5
前手动装箱和拆箱,装箱:基本类型->
包装类型,反之,拆箱jdk5
及以后有自动装箱和拆箱方式- 自动装箱底层调用的是
valueOf
方法,比如Integer.valueOf
- 其它包装类的用法类似,不一一举例
public class Integer01 {
public static void main(String[] args) {
//演示包装类和基本数据类型的相互转换,这里以int和Integer演示。
//1)jdk5前的手动装箱和拆箱方式,装箱:基本类型->包装类型,反之,拆箱
//手动装箱
int num1 = 10;
Integer integer = new Integer(num1); //方式一
Integer integer1 = Integer.valueOf(num1); //方式二
//手动拆箱
int i = integer1.intValue();
//2)jdk5 以后(含jdk5)的自动装箱和拆箱方式
//3)自动装箱底层调用的是 valueOf 方法,比如 Integer.valueOf
Integer integer2 = 33;
int num2 = integer2;
//4)其它包装类的用法类似,不一一举例
Double d = 3.3;
double d2 = d;
}
}
13.1.4 包装类 和 String 的相互转换
以 Integer
和 String
为例:
public class IntegerVSString {
public static void main(String[] args) {
//通过 Integer 和 String 的转换演示包装类与 String 类型的转换
//Integer -> String
Integer num1 = 33;
//方式一、
String str1 = num1 + "";
//str1 = 33 + ""; //以前的 int -> String类型, 自动装箱?
//方式二、
String str2 = num1.toString();
//方式三
String str3 = String.valueOf(num1); //底层也是 toString()
//str3 = new String(num1); //String 没有这种构造方法
//String 转 Integer
String str = "1233";
//方式一
Integer integer = Integer.parseInt(str); // parseInt() 返回的 int 类型,这里有自动装箱
//方式二
Integer integer1 = Integer.valueOf(str); //手动装箱
Integer integer2 = new Integer(str); // 手动装箱
}
}
13.1.5 Integer 和 Character 的常用方法
public class WrapperMethod {
public static void main(String[] args) {
//Integer 和 Character 的常用方法
System.out.println("Integer.MAX_VALUE = " + Integer.MAX_VALUE); //最大范围
System.out.println("Integer.MIN_VALUE = " + Integer.MIN_VALUE); //最小范围
System.out.println("Character.digit('1') = " + Character.isDigit('1')); //是不是数字
System.out.println("Character.isLetter('a') = " + Character.isLetter('a')); //是不是字母
System.out.println("Character.isUpperCase('A') = " + Character.isUpperCase('A')); //是不是大写
System.out.println("Character.isLowerCase('a') = " + Character.isLowerCase('a')); //是不是小写
System.out.println("Character.isSpace(' ') = " + Character.isWhitespace(' ')); //是不是空格
System.out.println("Character.toUpperCase('a') = " + Character.toUpperCase('a')); //转换成大写
System.out.println("Character.toLowerCase('A') = " + Character.toLowerCase('A')); //转换成小写
}
}
- 更多方法可以查看继承关系图
13.1.6 Integer 创建机制
- 自动装箱底层会调用
valueOf()
方法,只有当参数不在 [-128,127] 区间内,才会返回新的对象,否则返回的是IntegerCache
属性里与参数的值一致的对象
public class WrapperExercise01 {
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2= new Integer(1);
System.out.println(i1 == i2); //F 手动创建了对象,这里两个对象地址值不同
//这里自动装箱,底层调用的 valueOf()
//查看源码
/*public static Integer valueOf(int i) {
if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high) //这里有范围 -128 - 127
return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)]; //参数小于这个范围会返回现有的对象
return new Integer(i); //否则返回新对象
}*/
Integer i3 = 1;
Integer i4 = 1;
System.out.println(i3 == i4); //T 这里两个对象的引用都是一样
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6); //F 128不在IntegerCache的范围内,所以底层重新创建了对象
Integer i7 = 59;
int i8 = 59;
System.out.println(i7 == i8); //T 当有基本数据类型的时候比较的是数值
Integer i9 = 128;
int i10 = 128;
System.out.println(i9 == i10); //T 当有基本数据类型的时候比较的是数值
}
}
13.2 String 类
13.2.1 String 类的理解和创建对象
对象:
String
对象用于保存字符串,也就是一组字符序列- 字符串常量对象是双引号括起的字符序列,如 "hello" ,"world"
- 字符串的字符使用
Unicode
字符编码,一个字符不区分字母还是汉字占两个字节
类介绍:
String
类有很多构造器,构造器的重载String
类有很多构造器,构造器的重载,常用的有(更多的见文档):String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count)
String s5 = new String(byte[] b)
String
类实现了接口Serializable
(String
可以串行化:可以在网络传输);接口Comparable
(String 对象可以比较大小)String
是final
类,不能被其他的类继承String
有属性private final char value[];
用于存放字符串内容- 一定要注意:
value
是一个final
类型,且是一个数组,所以value
存的地址值不可以修改
即 :value
不能指向新的地址,但是单个字符内容是可以变化
public class String01 {
public static void main(String[] args) {
// 1. String 对象用于保存字符串,也就是一组字符序列
// 2. 字符串常量对象是双引号括起的字符序列,如 "hello" ,"world"
// 3. 字符串的字符使用 Unicode 字符编码,一个字符(不区分字母还是汉字)占两个字节
// 4. String 类有很多构造器,构造器的重载
// 常用的有(更多的见文档)
// String s1 = new String();
// String s2 = new String(String original);
// String s3 = new String(char[] a);
// String s4 = new String(char[] a,int startIndex,int count)
// String s5 = new String(byte[] b)
// 5. String 类实现了接口 Serializable【String 可以串行化:可以在网络传输】
// 接口 Comparable [String 对象可以比较大小]
// 6. String 是 final 类,不能被其他的类继承
// 7. String 有属性 private final char value[]; 用于存放字符串内容
// 8. 一定要注意:value 是一个 final 类型,且是一个数组,所以 value 存的地址值不可以修改
// 即 value 不能指向新的地址,但是单个字符内容是可以变化
// 1.String 对象用于保存字符串,也就是一组字符序列
// 看源码可知,字符串 value 是以 char 类型数组保存的
///** The value is used for character storage. */
//private final char value[];
String str1 = "hello";
str1 = new String("world");
// 8. 一定要注意:value 是一个 final 类型,且是一个数组,所以 value 存的地址值不可以修改
// 即 value 不能指向新的地址,但是单个字符内容是可以变化
final char value[] = {'h', 'e', 'l', 'l', 'o'};
value[0] = 'y'; //改里面存的值可以
//value = new char[2]; //将 value 引用指向新的 char 数组,不可用
}
}
13.2.2 String 类创建对象机制
两种创建对象方式:
- 直接赋值
String str = "hello"
- 用构造器
String str2 = new String("hello")
13.2.3 两种创建对象方式区别
- 方式一:先在常量池找有没有
"hello"
字符串- 如果有则直接传递地址值给引用
- 没找到则会创建一个,再把地址值传递给引用
- 方式二:先在堆中创建一个
String
类型的对象,再对value
属性进行初始化,然后在常量池里找"hello"
字符串- 如果找到了,直接把地址值传递给
value
,然后把堆空间的对象地址值传递给引用 - 如果没找到,则在常量池创建一个字符串,再进行地址值传递,最后传递给引用的都是堆空间的对象地址值
- 如果找到了,直接把地址值传递给
13.2.4 内存图分析
13.2.4 inner() 方法
作用:
- 返回的是常量池中与该 String 对象内容相同(通过
equals(Object o)
比较)的字符串的地址 - 如果常量池中没找到对应字符串,就会将字符串存进常量池,再返回该地址值
public class String02 {
public static void main(String[] args) {
String a = "hsp";
String b = new String("hsp");
System.out.println(a.equals(b)); //T 内容一致
System.out.println(a == b); //F 地址不一样
//intern() 源码
/*@return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.*/
//1.返回的是常量池中与该 String 对象内容相同(通过equals(Object o)比较)的字符串的地址
System.out.println(a == b.intern()); //T
System.out.println(b == b.intern()); //F 地址值不一样,一个是堆空间的,一个是常量池的
//2.如果常量池中没找到对应字符串,就会将字符串存进常量池,再返回该地址值
System.out.println("abc".intern().hashCode()); //96354
String c = "abc";
System.out.println(c.hashCode()); //96354
}
}
13.2.5 练习
13.2.6 字符串的特性
- String 是一个
final
类,代表不可变的字符序列 - 字符串是不可变的,一个字符串对象一旦被分配,其内容是不可变的
13.2.7 字符串拼接
- 两个字符串常量拼接:先判断字符串常量是否有引用指向,没有就创建拼接后的对象
- 两个字符串引用拼接:底层是创建了
StringBuilder
对象再调用append(str)
拼接,再调用toString()
创建拼接后的对象 - 规则:字符串常量拼接看池,字符串引用拼接看堆
学习思路:一定要看源码
public class StringProperty01 {
public static void main(String[] args) {
//1. 两个字符串常量拼接
//分析:底层做了优化,先判断字符串常量是否有引用指向,"hello" "world" 两个字符串常量没有引用指向,
// 所以直接创建"helloworld" 常量
String str1 = "hello" + "world";
//2. 两个字符串引用拼接
//Debug查看步骤:
// 1.创建一个 StringBuilder 对象,初始容量16个字符
// 2.调用 StringBuilder 的 append("hello"),返回一个 StringBuilder
// 3.调用 StringBuilder 的 append("carl"),返回一个 StringBuilder
// 4.调用 StringBuilder 的 toString(),返回一个 new String(value, 0, count) 对象
// 5.再把 "hellocarl" 的字符串对象传递给 str4 引用
//总结:底层是:StringBuilder strs = new StringBuilder(), strs.append("hello"), strs.append("carl")
// strs 是在堆中,并且 append 是在原来的字符串基础上追加的
// 规则:字符串常量拼接看池,字符串引用拼接看堆
String str2 = "hello";
String str3 = "carl";
String str4 = str2 + str3;
}
}
13.2.8 Debug 进入源码设置
13.2.9 字符串拼接面试题
- 字符串常量和字符串引用拼接
public class StringPropertyExercise01 {
String str = new String("hsp");
final char[] ch = {'j', 'a', 'v', 'a'};
public void change(String str, char ch[]) {
str = "java"; //修改局部变量 str 的引用,指向常量池的 "java"
ch[0] = 'h';
}
public static void main(String[] args) {
StringPropertyExercise01 ex = new StringPropertyExercise01();
ex.change(ex.str, ex.ch);
//Debug步骤:
// 1. String strs = new StringBuilder()
// 2. strs.append("hsp")
// 3. strs.append("and")
// 4. strs.toString() 返回 new String(value, 0, count)
// 总结:字符串引用和字符串拼接也是用通过 StringBuilder
System.out.print(ex.str + "and"); //ex.str 是属性 结果 hspandhava
System.out.println(ex.ch);
}
}
13.2.10 String 类常用方法
equals()
区分大小写,判断内容是否相等equalsIgnoreCase()
忽略大小写的判断内容是否相等length()
获取字符的个数,字符串的长度indexOf()
获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1lastIndexOf()
获取字符在字符串中最后1次出现的索引,索引从0开始,如找不到,返回-1substring()
截取指定范围的字符串trim()
去前后空格charAt()
获取某索引处的字符,注意不能使用Str[index]
这种方式
public class StringMethod01 {
public static void main(String[] args) {
String str1 = " hello ";
String str2 = " HeLLo ";
//● equals() 区分大小写,判断内容是否相等
System.out.println("str1.equals(str2) = " + str1.equals(str2)); //false
//● equalsIgnoreCase() 忽略大小写的判断内容是否相等
System.out.println("str1.equalsIgnoreCase(str2) = " + str1.equalsIgnoreCase(str2)); //true
//● length() 获取字符的个数,字符串的长度
System.out.println("str1.length() = " + str1.length()); //5
//● indexOf() 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1
System.out.println("str1.indexOf('l') = " + str1.indexOf('l')); //2
//● lastIndexOf() 获取字符在字符串中最后1次出现的索引,索引从0开始,如找不到,返回-1
System.out.println("str1.lastIndexOf('l') = " + str1.lastIndexOf('l')); //3
//● substring() 截取指定范围的字符串 含头不含尾
System.out.println("str1.substring(0, 4) = " + str1.substring(0, 4)); //hell
//● trim() 去前后空格
System.out.println("str1.trim() = " + str1.trim()); //hello
//● charAt() 获取某索引处的字符,注意不能使用Str[index]这种方式
System.out.println("str1.charAt(1) = " + str1.charAt(2)); //e
}
}
toUpperCase()
转大写toLowerCase()
转小写concat()
在后面拼接字符串replace()
替换字符串中的字符split()
分割字符串,对于某些分割字符,我们需要转义比如|
\\
等- 案例:
String poem= "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦”;
和 文件路径
- 案例:
compareTo()
比较两个字符串的大小 前者大则返回正数,后者大返回负数,相同返回0toCharArray()
转换成字符数组format()
格式字符串,按顺序替换指定字符串里的占位符,用对应格式变量%s
字符串%c
字符%d
整型%.2f
浮点型 保留两位小数
- 案例,将一个人的信息格式化输出
public class StringMethod02 {
public static void main(String[] args) {
String str1 = "Hello";
//● toUpperCase() 转大写
System.out.println("str1.toUpperCase() = " + str1.toUpperCase()); //HELLO
//● toLowerCase() 转小写
System.out.println("str1.toLowerCase() = " + str1.toLowerCase()); //hello
//● concat() 在后面拼接字符串
System.out.println("str1.concat(\",World\") = " + str1.concat(",World")); //Hello,World
//● replace() 替换字符串中的字符
System.out.println("str1.replace('e', 'a') = " +
str1.replace('e', 'a')); //Hallo
//● split() 分割字符串,对于某些分割字符,我们需要转义比如 | \\ 等
// ○ 案例:String poem= "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦”;
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String[] strings = poem.split(",");
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
// 和 文件路径.
poem = "E:\\aaa\\bbb";
String[] strings1 = poem.split("\\\\");
for (int i = 0; i < strings1.length; i++) {
System.out.println(strings1[i]);
}
//● compareTo() 比较两个字符串的大小 前者大则返回正数,后者大返回负数,相同返回0
// 分析:(1) 如果长度相同,并且每个字符也相同,就返回 0
// (2) 如果在进行比较时,可以区分字母大小或大小写就返回:
// if (c1 != c2) {
// return c1 - c2;
// }
// (3) 如果前面的部分都相同,就返回 str1.len - str2.len
String str2 = "hello,world";
System.out.println("str1.length() = " + str1.length()); //5
System.out.println("str2.length() = " + str2.length()); //11
System.out.println("str1.compareTo(str2) = " + str1.compareTo(str2)); //-32
//● toCharArray() 转换成字符数组
char[] chars = str1.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println("chars[i] = " + chars[i]);
}
//● format() 格式字符串 按顺序替换指定字符串里的占位符,用对应格式变量
// ○ %s 字符串
// ○ %c 字符
// ○ %d 整型
// ○ %.2f 浮点型 保留两位小数
//● 案例,将一个人的信息格式化输出
String name = "john";
int age = 10;
double score = 56.857;
char gender = '男';
//将所有的信息都拼接在一个字符串
String info = "我的信息是:姓名 %s, 年龄 %d, 分数 %.1f, 性别 %c";
//我的信息是:姓名 john, 年龄 10, 分数 56.9, 性别 男
System.out.println(String.format(info, name, age, score, gender));
}
}
13.3 StringBuffer 类
13.3.1 StringBuffer 类介绍
java.lang.StringBuffer
代表可变的字符序列,可以对字符串内容进行增删。- 很多方法与
String
相同,但StringBuffer
是可变长度的。StringBuffer
是一个容器。
StringBuffer
类继承关系
public class StringBuffer01 {
public static void main(String[] args) {
//1. StringBuffer 的直接父类 是 AbstractStringBuilder
//2. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化
//3. 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final
// 该 value 数组存放 字符串内容,因此存放在堆中的
//4. StringBuffer 是一个 final 类,不能被继承
//5. 因为 StringBuffer 字符内容是存在 char[] value, 所以变化(增加/删除)
// 不用每次都更换地址(即不是每次创建新对象), 所以效率高于 String
StringBuffer stringBuffer = new StringBuffer();
}
}
13.3.2 StringBuffer 和 String 的区别
- 内容:
String
保存的是字符串常量StringBuffer
保存的是字符串变量
- 是否可修改
String
里面的值不能更改,每次String
类的更新实际上就是更改String
对象引用的地址,效率较低private final char value[]
StringBuffer
里面的值可以更改,有一个缓存机制,每次StringBuffer
的更新实际上可以更新内容,不用每次更新地址,效率较高char[]value;
放在堆。
13.3.3 StringBuffer 和 String 相互转换
public class StringVSStringBuffer {
public static void main(String[] args) {
String str = "石头人";
//String -> StringBuffer
//方式一:构造器
StringBuffer stringBuffer = new StringBuffer(str);
//方式二:append() 在后面添加字符串,返回 StringBuffer 对象
StringBuffer stringBuffer1 = new StringBuffer();
StringBuffer hello = stringBuffer1.append("hello");
System.out.println(hello); //石头人hello
//StringBuffer -> String
//方式一:StringBuffer的toString
String s = stringBuffer.toString();
//方式二:String构造器
String s1 = new String(hello);
}
}
13.3.4 StringBuffer 类常用方法
package com.hspedu.stringbuffer_;
/**
* @author: Carl Zhang
* @create: 2021-11-29 16:17
*/
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer("hello,world");
//增 直接修改的堆空间的内容
stringBuffer.append(",张三丰");
System.out.println("stringBuffer = " + stringBuffer); //stringBuffer = hello,world,张三丰
System.out.println(stringBuffer.append(true).append(3)); //hello,world,张三丰true3
StringBuffer sb = new StringBuffer();
sb.append(null); //底层AbstractStringBuilder调用的appendNull()
//删 删除范围内的字符,含头不含尾
stringBuffer.delete(0, 5);
System.out.println("stringBuffer = " + stringBuffer); //,world,张三丰true3
//stringBuffer.delete(16, 17); //end > count
System.out.println("stringBuffer = " + stringBuffer); //异常StringIndexOutOfBoundsException
//改 用指定字符串替换范围内的字符,含头不含尾
stringBuffer.replace(0, 6, "hello");
System.out.println("stringBuffer = " + stringBuffer); //hello,张三丰true3
//查 查找指定的字符串串在字符串第一次出现的索引,如果找不到返回-1
System.out.println(stringBuffer.indexOf("hello")); //0
//插 在指定位置插入值,原来位置的字符串往后移
stringBuffer.insert(9, ',');
System.out.println("stringBuffer = " + stringBuffer); //hello,张三丰,true3
stringBuffer.insert(6, "world,");
System.out.println("stringBuffer = " + stringBuffer); //hello,world,张三丰,true3
//长度
System.out.println("stringBuffer.length() = " + stringBuffer.length()); //21
}
}
13.3.5 练习
package com.hspedu.stringbuffer_;
import java.util.Scanner;
/**
* @author: Carl Zhang
* @create: 2021-11-29 16:57
*/
public class StringBufferExercise02 {
public static void main(String[] args) {
/*
* 输入商品名称和商品价格,要求打印效果示例, 使用前面学习的方法完成:
* 商品名 商品价格
* 手机 123,564.59 //比如 价格 3,456,789.88
* 要求:价格的小数点前面每三位用逗号隔开, 在输出。
* */
//思路分析:
//1. 需要定义Scanner
//2. 用 String 变量保存用户输入的 name, price
//3. 需要用到StringBuffer的方法,将 price 转成 StringBuffer
//3. 从小数点的位置前三位起,倒序遍历 price 字符串
//4. 每三位就插入"," insert()
Scanner scanner = new Scanner(System.in);
//String price = "3456789.88";
System.out.print("请输入商品名:");
String name = scanner.next();
System.out.print("请输入价格:");
String price = scanner.next();
StringBuffer priceBuffer = new StringBuffer(price);
for (int i = priceBuffer.indexOf(".") - 3; i >= 0; i -= 3) {
priceBuffer.insert(i, ',');
}
//System.out.println("price = " + priceBuffer);
System.out.println("商品\t价格\n" + name + "\t" + priceBuffer);
}
}
13.4 StringBuilder 类
13.4.1 StringBuilder 类介绍
- 一个可变的字符序列。此类提供一个与
StringBuffer
兼容的 API,但不保证同步,(StringBuilder
不是线程安全)。该类被设计用作StringBuffer
的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类因为在大多数实现中,它比StringBuffer
要快[后面测]。- 在
StringBuilder
上的主要操作是append()
和insert()
方法,可重载这些方法,以接受任意类型的数据。
类继承关系
public class StringBuilder_ {
public static void main(String[] args) {
//1.StringBuilder 继承AbstractStringBuilder类
//2.实现了Serializable,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)
//3.StringBuilder 是final类,不能被继承
//4.StringBuilder 对象字符序列仍然是存放在其父类AbstractStringBuilder的 charl]value;
//因此,字符序列是堆中
//5.StringBuilder的方法,没有做互斥的处理,即没有 synchronized 关键字,因此在单线程的情况下使用
//StringBuilder
StringBuilder stringBuilder = new StringBuilder();
}
}
13.4.2 String、StringBuffer、StringBuilder 比较
StringBuilder
和StringBuffer
非常类似,均代表可变的字符序列,而且方法也一样String
:不可变字符序列,效率低,但是复用率高。StringBuffer
:可变字符序列、效率较高(增删)、线程安全,看源码StringBuilder
:可变字符序列、效率最高、线程不安全String
使用注意说明:string s = "a";
创建了一个字符串s += "b";
实际上原来的"a"
字符串对象已经丢弃了,现在又产生了一个字符串s + "b"
(也就是"ab"
)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大。影响程序的性能- 结论:如果我们对
String
做大量修改,不要使用String
13.4.3 String、StringBuffer 和 StringBuilder 的效率测试
package com.hspedu.stringbuilder_;
/**
* @author: Carl Zhang
* @create: 2021-12-01 10:40
*/
public class StringVsStringBufferVsStringBuilder {
public static void main(String[] args) {
long startTime = 0L;
long endTime = 0L;
StringBuffer buffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) { //拼接80000次
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer 的执行时间:" + (endTime - startTime)); //12
StringBuilder builder = new StringBuilder("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) { //拼接80000次
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder 的执行时间:" + (endTime - startTime)); //5
String text = "";
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) { //拼接80000次
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String 的执行时间:" + (endTime - startTime)); //4294
}
}
13.4.4 String、StringBuffer 和 StringBuilder 的选择
使用结论:
- 如果字符串存在大量的修改操作,一般使用
StringBuffer
或StringBuilder
- 如果字符串存在大量的修改操作,并在单线程的情况,使用
StringBuilder
(方法同StringBuffer一致
) - 如果字符串存在大量的修改操作,并在多线程的情况,使用
StringBuffer
- 如果我们字符串很少修改,被多个对象引用,使用
String
,比如配置信息等
13.5 Math 类
13.5.1 Math 类基本介绍
包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
13.5.2 Math 类常用方法
详见 JDK 文档(不要背!)
abs
绝对值pow
求幂ceil
向上取整floor
向下取整round
四舍五入sqrt
求开方random
求随机数max
求两个数的最大值min
求两个数的最小值
package com.hspedu.math;
/**
* @author: Carl Zhang
* @create: 2021-12-01 11:04
*/
public class Math01 {
public static void main(String[] args) {
//1.abs 绝对值
int abs = Math.abs(-9);
System.out.println(abs); //9
//2.ceil 向上取整
double ceil = Math.ceil(9.4);
System.out.println(ceil); //10.0
//3.floor 向下取整
double floor = Math.floor(8.8);
System.out.println(floor); //8.0
//4.round 四舍五入
long round = Math.round(5.6);
System.out.println(round); //6
//5.sqrt 求开方
double sqrt = Math.sqrt(9);
System.out.println(sqrt); //3.0
//6.random 求随机数 返回 0 - 1 的数,含0不含1
//思考:
//请写出获取a-b之间的一个随机整数,a,b均为整数?2-7
int a = 2;
int b = 7;
int rand = (int)(a + Math.random() * (b + 1 - a));
System.out.println(rand); //6
//7.max 求两个数的最大值
int max = Math.max(2, 888); //888
System.out.println(max);
//8.min 求两个数的最小值
int min = Math.min(2, -11);
System.out.println(min); //-11
}
}
13.6 Arrays 类
13.6.1 Arrays 类常用方法
toString()
返回数组的字符串表现形式 + [ ]sort()
自然排序顺序- 方法重载:自定义排序规则,
sort(arr, new Comparator(){...})
- 方法重载:自定义排序规则,
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author: Carl Zhang
* @create: 2021-12-01 15:01
*/
public class Array01 {
public static void main(String[] args) {
Integer[] nums = {1, 33, 0, 22, 8, 90};
//1. toString() 返回数组的字符串表现形式 + []
String s = Arrays.toString(nums);
System.out.println(s); //[1, 33, 0, 22, 8, 90]
//2.sort() 自然排序 顺序
Arrays.sort(nums);
System.out.println(Arrays.toString(nums)); //[0, 1, 8, 22, 33, 90]
//自定义排序规则
//看源码:
//1. 最终调用的是TimSort.sort(a, 0, a.length, c, null, 0, 0);
//2. 然后到 TimSort 类的 private static <T> void binarySort(T[] a,
// int lo, int hi, int start,Comparator<? super T> c)
//3. 根据动态绑定机制,访问传入的匿名内部类的 compare 方法
//while (left < right) {
// int mid = (left + right) >>> 1;
// if (c.compare(pivot, a[mid]) < 0) //根据compare方法返回数的正负来决定规则
// right = mid;
// else
// left = mid + 1;
//}
//4. 根据 public int compare(Object o1, Object o2) 返回的数的正负来决定排序规则,
// 体现了接口编程 + 动态绑定 + 匿名内部类的综合使用将来的底层框架和源码的使用方式,会非常常见
Arrays.sort(nums, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer)o1;
Integer i2 = (Integer)o2;
return i2 - i1;
}
});
System.out.println(Arrays.toString(nums)); //[90, 33, 22, 8, 1, 0]
}
}
模拟自定义排序
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author: Carl Zhang
* @create: 2021-12-01 16:25
*/
public class ArraySortCustom {
public static void main(String[] args) {
Integer[] nums = {3, 0, -1, 22, -11, 9};
//调用自定义排序方法
ArraySort.sortCustom(nums, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i2 - i1;
}
});
//打印数组
System.out.println(Arrays.toString(nums));
}
}
class ArraySort {
public static void sortCustom(Integer[] nums, Comparator c) {
Integer temp = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = 0; j < nums.length - i - 1; j++) {
//排序规则 根据返回的数的正负来判断
if (c.compare(nums[j], nums[j + 1]) > 0) {
temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
}
binarySearch()
通过二叉法在数组内查找某个数, 找到则返回对应下标copyOf()
将指定数组拷贝到指定长度的数组内,返回拷贝后的数组fiil()
用指定值填充指定数组的所有元素,可以理解为替换equals()
比较两个数组是否相等 返回 boolean 值asList()
将数组转换成 List集合 并返回
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @author: Carl Zhang
* @create: 2021-12-01 16:55
*/
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] nums = {1, 22, 33, 55, 133, 900};
//binarySearch() 通过二叉法在数组内查找某个数, 找到则返回对应下标
//找不到则 return -(low + 1);
//注意:该数组必须是排好正序的
int index = Arrays.binarySearch(nums, 33);
System.out.println(index);
//将数组排倒序
Arrays.sort(nums, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return (Integer) o2 - (Integer) o1;
}
});
//查找
index = Arrays.binarySearch(nums, 900);
//打印
System.out.println(index); //-7
//copyOf() 将指定数组拷贝到指定长度的数组内,返回拷贝后的数组
//1. 如果 newLength 小与原数组,就少拷贝元素
//2. 如果 newLength 大于原数组,就会给空余的位置默认值
//3. 如果 newLength < 0,就会抛异常 NegativeArraySizeException
Integer[] nums2 = Arrays.copyOf(nums, nums.length + 1);
System.out.println(Arrays.toString(nums2));
//fiil() 用指定值填充指定数组的所有元素,可以理解为替换
Integer[] num3 = new Integer[3];
Arrays.fill(num3, 100);
System.out.println(Arrays.toString(num3)); //[100, 100, 100]
//equals() 比较两个数组是否相等 返回 boolean 值
boolean result = Arrays.equals(nums, nums2);
System.out.println(result); //false
//asList() 将数组转换成 List集合 并返回
//1. List(编译类型) 是接口
//2. asList 运行类型是 java.util.Arrays$ArrayList
// 是 Arrays 类的 静态内部类 private static class ArrayList<E> extends AbstractList<E>
// implements RandomAccess, java.io.Serializable
List asList = Arrays.asList(num3);
System.out.println("asList = " + asList); //asList = [100, 100, 100]
System.out.println("asList.getClass() = " + asList.getClass()); //java.util.Arrays$ArrayList
}
}
13.7 System 类
13.7.1 System 类常用方法
exit()
:退出当前程序 ,参数 0 表示正常退出arraycopy()
:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf()
完成复制数组currentTimeMillis()
:返回当前时间距离1970-1-1的毫秒数运行垃圾回收机制System.gc()
:运行垃圾回收机制,(见 基础语法 8.9.5)
public class System_ {
public static void main(String[] args) {
//exit() 退出当前程序 ,参数 0 表示正常退出
System.out.println("Hello");
//System.exit(0); //0表示正常退出
System.out.println("World");
//arraycopy():复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
int[]src={1,2,3};
int[]dest=new int[3];
//源数组
//* @param src the source array.
//从源数组的起始坐标开始拷贝
//* @param srcPos starting position in the source array.
//目标数组
//* @param dest the destination array.
//目标数组的起始坐标
//* @param destPos starting position in the destination data.
//要拷贝的元素个数
//* @param length the number of array elements to be copied.
System.arraycopy(src,0,dest,0,3);
System.out.println(Arrays.toString(dest)); //[1, 2, 3]
//currentTimeMillis():返回当前时间距离1970-1-1的毫秒数
System.out.println(System.currentTimeMillis());
//System.gc() 运行垃圾回收机制
}
}
13.8 BigInteger 和 BigDecimal 类
13.8.1 应用场景
Biglnteger
适合保存比较大的整型BigDecimal
适合保存精度更高的浮点型(小数)
13.8.2 常用方法
add()
加subtract()
减multiply()
乘divide()
除
public class BigInteger_ {
public static void main(String[] args) {
//保存大数时用long存不了 Long number too large
//long l = 999999999999999999999999999l;
//用BigInteger保存大数
BigInteger bigInteger = new BigInteger("999999999999999999999999999");
System.out.println("bigInteger = " + bigInteger);
BigInteger bigInteger1 = new BigInteger("100000000000000000000000000");
//add加
BigInteger add = bigInteger.add(bigInteger1);
System.out.println("add = " + add);
//subtract减
BigInteger subtract = bigInteger.subtract(bigInteger1);
System.out.println("subtract = " + subtract);
//multiply乘
BigInteger multiply = bigInteger.multiply(bigInteger1);
System.out.println("multiply = " + multiply);
//divide除
BigInteger divide = bigInteger.divide(bigInteger1);
System.out.println("divide = " + divide);
}
}
public class BigDecimal_ {
public static void main(String[] args) {
//保存精度很高的数用double表示不了
double d = 99.99999999999999999d;
System.out.println(d); //100.0
//用BigDecimal
BigDecimal bigDecimal = new BigDecimal("99.99999999999999999");
System.out.println(bigDecimal);
//add() 加,传入BigDecimal对象
BigDecimal bigDecimal1 = new BigDecimal("0.00000000000000001");
BigDecimal add = bigDecimal.add(bigDecimal1);
System.out.println(add);
//subtract减
BigDecimal subtract = bigDecimal.subtract(bigDecimal1);
System.out.println(subtract);
//multiply乘
BigDecimal multiply = bigDecimal1.multiply(bigDecimal1);
System.out.println(multiply);
//divide除
BigDecimal divide = bigDecimal.divide(bigDecimal1);
System.out.println(divide);
}
}
13.9 日期类
13.9.1 第一代日期类 Date
介绍:
Date
类,获取当前日期对象,精确到毫秒SimpleDateFormat
类,对日期进行格式化和解析- 格式化:日期 -> 文本
format()
- 解析:文本 -> 日期
parse()
- 格式化:日期 -> 文本
常用方法及案例:
public class Date01 {
public static void main(String[] args) throws ParseException {
//第一代日期类 Date
//1. 获取当前系统时间
// 默认格式是外国格式,可以通过 SimpleDateFormat 进行格式化
Date date = new Date();
System.out.println(date); //Thu Dec 02 11:25:28 CST 2021
//* 通过毫秒数(long类型)获取日期
Date date1 = new Date(1638416256789l);
System.out.println(date1); //Thu Dec 02 11:32:44 CST 2021
//2. 将Date格式化成String
// * 构造器后面可填的字母见 JDK
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String s = simpleDateFormat.format(date);
System.out.println("当前时间:" + s);
//3.将文本转换成 Date类型
// * 转换后的文本格式为Date的默认格式
// * 可通过format方法再次格式化
// * 注意:要转换的文本必须和simpleDateFormat的格式一致,否则会抛异常ParseException
String time = "2021-12-02 11:32:44 星期四";
Date parse = simpleDateFormat.parse(time);
System.out.println(parse); //Thu Dec 02 11:32:44 CST 2021
}
}
13.9.2 第二代日期类 Calendar
- 类声明:
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Calendar
类是一个抽象类,它为特定瞬间与一组诸如YEAR
、MONTH
、DAY_OF_MONTH
、HOUR
等日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法。- 例:获取年份
int i = calendar.get(Calendar._YEAR_);
- 例:获取年份
13.9.3 第三代日期类 LocalDateTime
前几代日期类的不足:
JDK 1.0
中包含了一个java.util.Date
类,但是它的大多数方法已经在JDK 1.1
引入Calendar
类之后被弃用了。- 而
Calendar
也存在问题是:- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:
Date
中的年份是从1900开始的,而月份都从0开始。 - 格式化:格式化只对
Date
有用,Calendar
则不行。 - 此外,它们也不是线程安全的;不能处理闰秒等(每隔2天,多出1s
JDK8
引入了新的日期类 LocalDateTime
LocalDateTime
** 介绍:**
LocalDate
只包含日期,可以获取年、月、日字段LocalTime
只包含时间,可以获取时、分、秒字段LocalDateTime
包含日期+时间,可以获取日期和时间字段
DateTimeFormatter
类:类似于 SimpleDateFormat
可对日期进行格式化
public class LocalDateTime_ {
public static void main(String[] args) {
//1. 使用 now() 返回表示当前日期时间的对象
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime); //2021-12-02T14:19:41.629
//2. 使用 DateTimeFormatter 格式化LocalDateTime对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String time = dateTimeFormatter.format(localDateTime);
System.out.println(time); //2021-12-02 14:23:21
//获取其他时间字段
System.out.println("年:" + localDateTime.getYear());
System.out.println("月:" + localDateTime.getMonth());
System.out.println("月:" + localDateTime.getMonthValue());
System.out.println("日:" + localDateTime.getDayOfMonth());
System.out.println("时:" + localDateTime.getHour());
System.out.println("分:" + localDateTime.getMinute());
System.out.println("秒:" + localDateTime.getSecond());
//提供 plus 和 minus 方法可以对当前时间进行加或者减
//看看 890 天后,是什么时候 把 年月日-时分秒
LocalDateTime plusDays = localDateTime.plusDays(890);
String format = dateTimeFormatter.format(plusDays);
System.out.println("890 天后是" + format);
//看看在 3456 分钟前是什么时候,把 年月日-时分秒输出
LocalDateTime localDateTime1 = localDateTime.minusMinutes(3456);
String format1 = dateTimeFormatter.format(localDateTime1);
System.out.println("3456 分钟前是" + format1);
}
}
更多方法查看JDK文档
public class LocalDateTime02 {
public static void main(String[] args) {
//MonthDay类:检查重复时间
//是否是闰年
//增加日期的某个部分
//使用plus方法测试增加时间的某个部分
//使用minus方法测试查看一年前和一年后的日期
MonthDay now = MonthDay.now();
System.out.println(now); //--12-02
MonthDay now1 = MonthDay.now();
System.out.println(now.equals(now1));
//是否是闰年
LocalDateTime ldt = LocalDateTime.now();
boolean leapYear = ldt.toLocalDate().isLeapYear();
System.out.println(leapYear); //false
}
}
13.9.4 Instant 时间戳
- 类似于
Date
- 提供了一系列和
Date
类转换的方式 Instant —> Date
:Date date=Date.from(instant);
Date —> Instant
:Instant instant=date.tolnstant();
public class Instant_ {
public static void main(String[] args) {
//1.通过 静态方法 now() 获取表示当前时间戳的对象
Instant now = Instant.now();
System.out.println(now); //2021-12-02T06:30:48.638Z
//2. 通过 from 可以把 Instant 转成 Date
Date from1 = Date.from(now);
System.out.println("from1 = " + from1); //Thu Dec 02 14:33:00 CST 2021
//3. 通过 toInstant() 将 date 转换成 Instant
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("instant = " + instant); //2021-12-02T06:36:59.433Z
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南