一、包装类
1.1 包装类的分类
| 基本数据类型 | 包装类 |
|---|---|
| boolean | Boolean |
| char | Character |
| byte | Byte |
| short | Short |
| long | Long |
| int | Integer |
| float | Float |
| double | Double |
- 针对八种基本定义相应的引用类型——包装类
- 有了类的特点,就可以调用类中的方法
>> 继承体系图:


1.2 包装类和基本数据的转换
jdk5 前的手动装箱和拆箱方式,装箱:基本类型 -> 包装类型 ,反之,拆箱
//jdk5 之前:手动装箱和拆箱//手动装箱 int -> Integerint n1 = 100;Integer integer = new Integer(n1);Integer integer1 = Integer.valueOf(n1);//手动拆箱 Integer -> intint i = integer.intValue();
jdk 以后(含 jdk5)的自动装箱和拆箱方式
//jdk5 之后:自动装箱和拆箱//自动装箱 int -> Integerint n2 = 200;Integer integer2 = n2; //底层使用的仍然是 Integer.valueOf()//自动拆箱 Integer -> intint n3 = integer2;
自动装箱底层调用的是 valueOf 方法,比如:Integer.valueOf()
- 其他包装类的用法类似
⏱ 小练习
下面代码是否正确?
Double d = 100d; //ok.自动装箱 Double.valueOf(100d);
Float f = 1.5f; //ok.自动装箱 Float.valueOf(1.5f);下面两段代码输出结果相同吗?各自输出什么?
Object obj1 = true?new Integer(1) : new Double(2.0); //
System.out.println(obj1); //输出1.0 三元运算符整条语句一起参与运算
Object obj2;
if(true)
obj2 = new Integer(1);
else
obj2 = new Double(2.0);
System.out.println(obj2); //输出1 分别运算
1.3 包装类型 和 String类型 的相互转换
public class WrapperVsString {public static void main(String[] args) {//包装类(Integer) -> StringInteger i1 =100; //自动装箱String str1 = i1 + ""; //方式1String str2 = i1.toString(); //方式2String str3 = String.valueOf(i1); //方式3//String -> 包装类(Integer)Integer i2 = Integer.parseInt(str1); //返回的是int类型,自动装箱到IntegerInteger i3 = new Integer(str1); //方式2}}
1.4 Integer类 和 Character类 的常用方法
System.out.println(Integer.MIN_VALUE); //返回最小值System.out.println(Integer.MAX_VALUE); //返回最大值System.out.println(Character.isDigit('a')); //判断是不是数字System.out.println(Character.isLetter('a')); //判断是不是字母System.out.println(Character.isUpperCase('a')); //判断是不是大写System.out.println(Character.isLowerCase('a')); //判断是不是小写System.out.println(Character.isWhitespace('a')); //判断是不是空格System.out.println(Character.toUpperCase('a')); //转成大写System.out.println(Character.toLowerCase('A')); //转成小写
Integer类面试题1
看看下面代码,输出结果是什么?并分析原因
public void method() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //False
Integer m = 1; //底层 Integer.valueOf(1) -> 阅读源码
Integer n = 1;
System.out.println(m == n); //True 分析底层源码
Integer x = 128;
Integer y = 128;
System.out.println(x == y); //False
}
Integer类面试题2
看看下面代码输出什么?
public static void main(String[] args) {
//示例一
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);
//示例二
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);
//示例三
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6);
//示例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);
//示例五
Integer i9 = 127;
Integer i10 = new Integer(127);
System.out.println(i9 == i10);
//示例六
Integer i11 = 127;
int i12 = 127;
System.out.println(i11 == i12);
//示例七
Integer i13 = 128;
Integer i14 = 128;
System.out.println(i13 == i14);
}
小结:
- 形如:Integer m = 1; 虽然会自动装箱,底层还是调用了 valueOf()方法,但是根据装入的值不不同,如果装入的值在 -128 ~ 127 范围内,则不会创建对象,直接返回数值,否则创建一个新的对象返回。
- ==比较运算时,只要有一方为 int 类型,则比较的是数值是否相等,而不是地址是否相同
二、String 类
2.1 String类的理解和创建对象
- String 对象用于保存字符串,也就是一组字符序列
- 字符串常量对象是用双引号括起来的字符序列。例如:”你好”、”12.98”、”boy”等
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
- 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可以串行化:可以在网络传输】
- String类 实现了接口 Comparable【String对象可以互相比较】
- String 是 final 类,不能被其他类继承
- String 有属性 private final char value[]; 用于存放字符串内容
- 一定要注意:value 是一个 final类型,不可以修改【指向的地址】
final char[] value = {'a','b','c'};value[1] = 'D'; //可以改变数组内的值char[] v2 = {'t','o','m'};value = v2; //错误,final类型不能改变地址指向
2.2 创建 String对象的两种方式
- 方式一:直接赋值 String s = “java”;
- 方式二:调用构造器 String s = new String(“java”);
区别:
- 方式一:先从常量池查看是否有”java”数据空间,如果有,直接访问;如果没有则创建,然后指向。s 最后指向的是常量池的空间地址。
- 方式二:先在堆中创建空间,里面维护了 value 属性,指向常量池的 “java” 空间。如果常量池没有 “java”,重新创建,如果有,直接通过 value 指向。最终指向的是堆中的空间地址。
- 两种方式的内存分布图


小练习
- 判断下面代码输出结果:
String a = “abc”;
String b = “abc”;
System.out.println(a.equals(b));
System.out.println(a == b);
String c= new String(“abc”);
String d = new String(“abc”);
System.out.println(c.equals(d));
System.out.println(c == b);
- 判断下面代码的输出结果:
String a = “java”;
String b = new String(“java”);
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a == b.intern());
System.out.println(b == b.intern());
知识点:intern() 方法的作用是返回String对象所指向常量池空间元素的地址
- 测试题
String s1 = “hspedu”;
String s2 = “java”;
String s3 = “java”;
String s4 = new String(“java”);
System.out.println(s2 == s3);
System.out.println(s2 == s4);
System.out.println(s2.equals(s4));
System.out.println(s1 == s2);
- 测试题
Person p1 = new Person();
p1.name = “hspedu”;
Person p2 = new Person();
p2.name = “hspedu”;
System.out.println(p1.name.equals(p2.name)); //t
System.out.println(p1.name == p2.name); //t
System.out.println(p1.name == “hspedu”); //True “hspedu”在参与==运算时返回的就是在常量池中的地址
String s1 = new String(“bcde”);
String s2 = new String(“bcde”);
System.out.println(s1 == s2); //f
// 验证"java"在参与 ==运算 时返回的就是在常量池中的地址String a = "java";System.out.println(a.hashCode());System.out.println("java".hashCode());
2.3 字符串的特性
- String 是一个 final类,代表不可变的字符序列
- 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
例题:以下语句创建了几个对象?(2个)
String s1 = “hello”;
s1 = “haha”;
面试题1
String a = “hello” + “abc”;
创建了几个对象?(1个)
解析:编译器在底层会自动将+号两边的字符串拼接成一个字符串的优化,会判断创建的常量池对象,是否有引用指向。
面试题2
String a = “hello”;
String b = “abc”;
String c = a + b;
创建了几个对象?(3个)
解读:底层实现过程
- 先创建一个 StringBuilder sb = StringBuilder()
- 执行 sb.append(“hello”)
- 执行 sb.append(“abc”)
- 执行 String c = sb.toString()
- 最后 c 指向的是堆中的对象 (String) value[] —再指向—> 池中的 “helloabc”
重要规则:常量相加,看的是池;变量相加,看的是堆
测试题3
下面代码输出什么?并说出原因
String s1 = “hspedu”;
String s2 = “java”;
String s5 = “hspedujava”;
String s6 = (s1 + s2).intern();
System.out.println(s5 == s6); //T
System.out.println(s5.equals(s6)); //T
测试题4
下面程序运行的结果是什么?可以在纸上画出内存布局图加以分析。
public class StringExercise04 {
public static void main(String[] args) {
Test1 ex = new Test1();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + “ and “);
System.out.println(ex.ch);
}
}
class Test1 {
String str = new String(“hsp”);
final char[] ch = {‘j’,’a’,’v’,’a’};
public void change(String str, char ch[]) {
str = “java”;
ch[0] = ‘h’;
}
}
2.4 String类的常见方法
String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此Java设计者还提供了StringBuilder 和 StringBuffer 来增强 String 的功能,并提高效率。
看如下代码,分析执行过程
String s = new String(“”);
for(int i = 0; i < 80000; i++) {
s += “hello”;
}
常用方法一览:
| method | 作用 |
|---|---|
| equals | 区分大小写,判断内容是否相等 |
| equalsIgnoreCase | 忽略大小写,判断内容是否相等 |
| length | 获取字符个数,字符串的长度 |
| indexOf | 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1 |
| lastIndexOf | 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回-1 |
| substring | 截取指定范围的子串 |
| trim | 去前后空格 |
| charAt | 获取某索引处的字符,注意不能使用 Str[index]这种方式 |
| toUpperCase | 将字符串转成大写 |
| toLowerCase | 将字符串转成小写 |
| concat | 连接两个字符串 |
| compareTo | 比较两个字符串 |
| toCharArray | 转换成字符数组 |
| format | 格式化字符串 %s 字符串 %c 字符 %d 整型 %.2f 浮点型 |
| replace | 替换字符串中的字符 |
| split | 分割字符串,对于某些分割字符,我们需要转义字符 \ |
public class StringMethod {public static void main(String[] args) {String a = "java";String b = "JAVA";System.out.println(a.equals(b));System.out.println(a.equalsIgnoreCase(b));System.out.println(a.length());System.out.println(a.charAt(2));System.out.println(a.indexOf('a'));System.out.println(a.lastIndexOf('a'));String c = "i am learning java!";String d = c.substring(2); //一个参数:从索引为2开始,截取到字符串尾System.out.println(d);String e = c.substring(2,6); //两个参数:从索引2开始,截取至索引为(6-1)//辅助记忆: 左闭右开 [2,6)System.out.println(e);System.out.println(" j a v a ");System.out.println(" j a v a ".trim()); //去首尾空格,不去中间空格System.out.println(a.toUpperCase()); //全部转为大写System.out.println(b.toLowerCase()); //全部转为小写System.out.println(a.concat(b)); //拼接两字符串String g = "贾宝玉 and 林黛玉 林黛玉 林黛玉";System.out.println(g.replace("林黛玉","薛宝钗")); //替代字符串内容String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";String[] split = poem.split(","); //以,为标准,对字符串进行分割,返回的是字符串数组String fileA = "E:\\aaa\\bbb";String[] split2 = fileA.split("\\|");String[] split3 = fileA.split("\\\\");for (int i = 0; i < split.length; i++) {System.out.println(split[i]);}for (int i = 0; i < split2.length; i++) {System.out.println(split2[i]);}for (int i = 0; i < split3.length; i++) {System.out.println(split3[i]);}String bj = "jchk";//比较过程:// (1) 先获取两字符串长度,取最小值min// (2) 从索引为0开始依次比较两字符串,若出现不同值则返回(前一个字符对应编码值 - 后一个字符对应编码值)的结果// (3) 若在比较到(min-1)索引都相同,则返回(前一个字符串长度 - 后一个字符串长度)的结果// (4) 两字符串相等 返回0System.out.println(a.compareTo(bj));char[] chars = c.toCharArray(); //将字符串转换成字符数组for (int i = 0; i < chars.length; i++) {System.out.println(chars[i]);}// format 格式化字符串/* 占位符有* %s 字符串 %c 字符 %d 整型 %.2f 浮点型**/String name = "john";int age = 10;double score = 98.3 / 3;char gender = '男';String info = "我的名字是" + name + " 年龄是" + age + ",成绩是" + score + " 性别是" + gender + "。希望大家喜欢我!";System.out.println(info);String information = "我的名字是%s 年龄是%d,成绩是%.2f 性别是%c。希望大家喜欢我!";String info2 = String.format(information,name,age,score,gender);System.out.println(info2);}}
三、StringBuffer 类
3.1 基本介绍
java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
很多方法与 String 相同,但 StringBuffer 是可变长度的
StringBuffer 是一个容器
3.2 StringBuffer 特点
- StringBuffer 是 final 类,不能被其他类继承
- 实现了接口 Serializable【可以保存到文件,或网络传输】
- 继承了抽象类 AbstractStringBuilder
- AbstractStringBuilder 有属性 char[] value 不是 final 类型,用于存放字符串内容,存放在堆中
- 因为StringBuffer 字符内容是存在 char[] value,所以发生变化(增加/删除)不用每次都更换地址(即不是每次都创建新对象),所以效率高于String
3.3 String VS StringBuffer
- String 保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低
- StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高,值保存在堆中
3.4 StringBuffer 构造器
| StringBuffer( ) | 构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符 |
|---|---|
| StringBuffer(CharSequence seq) | 构造一个字符串缓冲区,它包含与指定的CharSequence相同的字符 |
| StringBuffer(int capacity) | 构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对char[]大小进行指定 |
| StringBuffer(String str) | 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容,容量为指定字符串长度+16 |
3.5 String 和 StringBuffer 相互转换
String -> StringBuffer
String s = “hello”;
方式一:StringBuffer b1 = new StringBuffer(s);
方式二:StringBuffer b2 = new StringBuffer();
b2.append(s);
StringBuffer -> String
方式一:String s2 = b1.toString();
方式二:String s3 = new String(b1);
3.6 StringBuffer类 常见方法
| method | 作用 |
|---|---|
| append | 在字符串末尾增加内容 |
| delete(start,end) | 删除字符串内容 |
| replace(start,end,String) | 更改字符串内容 |
| indexOf | 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1 |
| lastIndexOf | 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回-1 |
| insert | 在字符串中插入内容 |
| length | 获取字符串长度 |
public class StringBufferMethod {public static void main(String[] args) {StringBuffer sbr = new StringBuffer("hello");sbr.append(','); //增加sbr.append("张三丰").append(100).append(true).append(10.5);System.out.println(sbr);sbr.delete(5,9); //删除 [5,9) 左闭右开 删除索引5-8的字符System.out.println(sbr);sbr.replace(0,5,"java"); //替换索引0-4的字符System.out.println(sbr);System.out.println(sbr.indexOf("10"));sbr.insert(4,"hello"); //在索引3和4之间插入字符内容System.out.println(sbr);System.out.println(sbr.length());}}
练习题1
看下面代码输出什么?为什么?
public class StringBufferExercise01 {public static void main(String[] args) {String str = null;StringBuffer sb = new StringBuffer();sb.append(str);System.out.println(sb.length());System.out.println(sb);StringBuffer sb1 = new StringBuffer(str);System.out.println(sb1);}}
知识点:StringBuffer使用 append() 方法时,如果传入的是 null,就会将null 转换成 “null”字符串传入,
但是构造器中传入 null 的 String对象,就会抛出空指针异常,原因是底层代码中的 super(str.length() + 16)。
练习题2
输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成:
商品名 商品价格
手机 123,456.59
要求:价格的小数点前面每三位用逗号隔开
public class StringBufferExercise02 {public static void main(String[] args) {StringBuffer name = new StringBuffer("手机");StringBuffer price = new StringBuffer("1123564.59");int point = price.lastIndexOf(".");for (int i = point - 3; i > 0 ; i -= 3) {price.insert(i,",");}System.out.println("商品名\t商品价格\n" + name + "\t" + price);}}
四、StringBuilder 类
4.1 基本介绍
一个可变的字符序列。此类提供一个与 StringBuffer 兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer 要快。
在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。
4.2 StringBuilder 特点
- StringBuilder 是final 类,不能被其他类继承
- 继承了 AbstractStringBuilder,属性 char[] value,内容存到 value
- 实现了接口 Serializable【可以保存到文件,或网络传输】,序列化【可以保存类型和数据本身】
- StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字的处理,因此在单线程的情况下使用
4.2 StringBuilder 常见方法
StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer一样。
4.3 String、StringBuilder、StringBuffer 的比较
- StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样。
- String:不可变字符序列,效率低,但是复用性高。
- StringBuffer:可变字符序列,效率较高(增删)、线程安全。
- StringBuilder:可变字符序列,效率最高,线程不安全。
- String 使用注意:
- String s = “a”; //创建了一个字符串
- s += “b”; //实际上原来的 “a”字符串对象已经丢弃了,现在又产生一个字符串s + “b”(也就是”ab”)。如果多次执行这些改变字符串的内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能
- 结论:如果我们对String 做大量修改,不要使用String
String、StringBuilder、StringBuffer 的效率测试
public class StringBuilder01 {public static void main(String[] args) {long startTime = 0L;long endTime = 0L;startTime = System.currentTimeMillis();StringBuffer buffer = new StringBuffer("");for (int i = 0; i < 80000; i++) {buffer.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuffer的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();StringBuilder builder = new StringBuilder("");for (int i = 0; i < 80000; i++) {builder.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuilder的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();String text = "";for (int i = 0; i < 80000; i++) {text = text + i;}endTime = System.currentTimeMillis();System.out.println("StringBuffer的执行时间:" + (endTime - startTime));}}
String、StringBuilder、StringBuffer 的选择
使用原则,结论:
- 如果字符串存在大量的修改操作,一般使用 StringBuffer 或者 StringBuilder
- 如果字符串存在大量的修改操作,并且在单线程的情况,使用 StringBuilder
- 如果字符串存在大量的修改操作,并且在多线程的情况,使用 StringBuffer
- 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等
五、Math 类
5.1 基本介绍
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
5.2 Math类常见方法(静态方法)
| method | 作用 |
|---|---|
| abs | 取绝对值 |
| pow | 求幂 |
| ceil | 向上取整 |
| floor | 向下取整 |
| round | 四舍五入 |
| sqrt | 求开方 |
| random | 获取随机数 |
| max | 取最大值 |
| min | 取最小值 |
public class MathMethod {public static void main(String[] args) {//看看Math常用的方法(静态方法)//1.abs 绝对值int abs = Math.abs(-9);System.out.println(abs);//2.pow 求幂double pow = Math.pow(2,4);System.out.println(pow);//3.ceil 向上取整 返回大于等于该参数的最小整数double ceil = Math.ceil(-3.0001);System.out.println(ceil);//4.floor 向下取整 返回小于等于该参数的最大整数double floor = Math.floor(-4.999);System.out.println(floor);//5.round 四舍五入 Math.floor(该参数+0.5)double round = Math.round(-5.501);System.out.println(round);//6.sqrt 开平方double sqrt = Math.sqrt(9.0);System.out.println(sqrt);//7.0 random 求随机数// 获取 a - b 之间的一个随机整数,a,b均为整数int a = 2;int b = 7;double x = 0;for (int i = 0; i < 50; i++) {x = (int)(Math.random() * (b+1-a) + a);System.out.println(x);}}}
六、Arrays类
6.1 基本介绍
Arrays 里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。
6.2 Arrays 常见方法
| method | 作用 |
|---|---|
| sort | 自然排序,从小到大 |
| toString | 转成字符串 |
| binarySearch | 二分查找 |
| copyOf | 数组拷贝 |
| fill | 数组填充 |
| equals | 数组比较 |
| asList | 将一组值,转换成list |
package com.hspedu.arrays_;import java.util.Arrays;import java.util.Comparator;import java.util.List;/*** @author HarborGao* @version 1.0*/public class Arrays01 {public static void main(String[] args) {Integer arr[] = {1, 5, 10, 8, 6, 22};System.out.println(Arrays.toString(arr));Arrays.sort(arr, 0, 4); //指定索引范围内自然排序System.out.println(Arrays.toString(arr));Arrays.sort(arr); //自然排序 从小到大System.out.println(Arrays.toString(arr));int find = Arrays.binarySearch(arr,11);System.out.println(find);// 排序//1. 可以直接使用冒泡排序,也可以直接使用Arrays提供的sort方法排序//2. 因为数组是引用类型,索引进行sort排序后,会直接影响到实参 arr//3. sort 重载的,也可以通过传入一个接口 Comparator 实现定制排序//4. 调用定制排序时,传入两个参数 (1) 排序数组 arr// (2) 实现了Comparator接口的匿名内部类,要求实现 compare 方法//5. 这里体现了接口编程的一种方式Arrays.sort(arr, new Comparator() {@Overridepublic int compare(Object o1, Object o2) {Integer i1 = (Integer) o1;Integer i2 = (Integer) o2;return i2 - i1;}});System.out.println(Arrays.toString(arr));System.out.println("==自定义排序==");int[] arr2 = {1, -1, 5, 3, 8, 10};// bubble01(arr2);bubble02(arr2, new Comparator() {@Overridepublic int compare(Object o1, Object o2) {int i1 = (Integer) o1;int i2 = (Integer) o2;return i2 - i1;}});System.out.println(Arrays.toString(arr2));Integer arr3[] = {10, 5, 2, 1};int index = Arrays.binarySearch(arr3,1, new Comparator(){@Overridepublic int compare(Object o1, Object o2) {Integer n1 = (Integer) o1;Integer n2 = (Integer) o2;return n2 - n1;}});System.out.println(index);//copyOf 数组拷贝Integer[] newArr = Arrays.copyOf(arr,arr.length - 1 );System.out.println(Arrays.toString(newArr));//fill 数组填充Integer[] num = {1,9,3};Arrays.fill(num,99); //用99替换数组所有值System.out.println(Arrays.toString(num));//equals 数组比较Integer[] num2 = {99,99,99};System.out.println(Arrays.equals(num,num2));//asList 将一组值,转换成list//解读://1. asList方法,会将(2,3,5,7,9)数据转成一个List集合//2. 返回的 asList 编译类型 List(接口)//3. asList 运行类型 java.util.Arrays#ArraysList,是Arrays类的静态内部类List asList = Arrays.asList(2,3,5,7,9);System.out.println("asList = " + asList);}//冒泡排序public static void bubble01(int[] arr) {int temp = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}//冒泡排序 + 定制public static void bubble02(int[] arr, Comparator c) {int temp = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (c.compare(arr[j], arr[j + 1]) > 0) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}}/*使用binarySearch时1. 如果传入两个参数,第一个参数是数组,第二个参数是要查找的值,数组必须是有序递增的2. 如果传入三个参数,第一个参数是数组,第二个参数是要查找的值,第三个参数是匿名内部类Comparator数组必须是有序(递增或递减)的,匿名内部类重写compare方法用于定制查询3. 如果传入四个参数,第一个参数是数组,第二个参数是起始索引,第三个是结束索引,第四个是要查找的值用于在指定索引范围内查找,要求数组必须是有序递增的3. 查找策略依据以下底层源码,如果找不到,返回负数,代表的是该值应该在的位置public static int binarySearch(int[] a, int key) {return binarySearch0(a, 0, a.length, key);}private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {int low = fromIndex; // 0int high = toIndex - 1; // a.length - 1while (low <= high) {int mid = (low + high) >>> 1;int midVal = a[mid];if (midVal < key)low = mid + 1;else if (midVal > key)high = mid - 1;elsereturn mid; // key found}return -(low + 1); // key not found.}*/
6.3 小练习
案例:自定义Book类,里面包含 name 和 price,。要求使用两种方式排序,分别按price 排序(从大到小)和按书名排序(从长到短)。 Book[] books = 4本书对象。
其中一种使用前面学习过的传递,实现Comparator接口匿名内部类,也称为定制排序。
package com.hspedu.arrays_;import java.util.Arrays;import java.util.Comparator;/*** @author HarborGao* @version 1.0*/public class ArraysExercise01 {public static void main(String[] args) {Book[] books = new Book[4];books[0] = new Book("红楼梦~~~~", 100);books[1] = new Book("金瓶梅~", 90);books[2] = new Book("青年文摘~", 5);books[3] = new Book("java从入门到放弃", 300);//方法一 sort方法// Arrays.sort(books, new Comparator() {// @Override// public int compare(Object o1, Object o2) {// Book book1 = (Book) o1;// Book book2 = (Book) o2;// double res = book2.getPrice() - book1.getPrice();// if (res > 0) {// return 1;// } else if (res < 0) {// return -1;// } else {// return 0;// }// }// });// System.out.println(Arrays.toString(books));//方法二 冒泡排序for (int i = 0; i < books.length; i++) {for (int j = 0; j < books.length - i - 1; j++) {if (books[j].getName().length() - books[j + 1].getName().length() < 0) {Book temp = books[j];books[j] = books[j + 1];books[j + 1] = temp;}}}System.out.println(Arrays.toString(books));}}class Book {private String name;private double price;public Book(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;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", price=" + price +'}';}}
七、System 类
7.1 System类常见方法
| method | 作用 |
|---|---|
| exit | 退出 |
| arraycopy | 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf |
| currentTimeMillis | 返回当前时间距离1970-1-1的毫秒数 |
| gc | 运行垃圾回收机制 |
八、BigInteger 和 BigDecimal 类
8.1 应用场景
- BigInteger 适合保存比较大的整型
- BigDecimal 适合保存精度更高的浮点型
8.2 BigInteger 和 BigDecimal 类常见方法
| method | 作用 |
|---|---|
| add | 加 |
| subtract | 减 |
| multiply | 乘 |
| divide | 除 |
public static void main(String[] args) {//当编程中需要使用很大的整数,long不够用//可以使用 BigInteger类// long l = 16546546464646464159999l;BigInteger bigInteger = new BigInteger("16546546464646464159999");BigInteger bigInteger1 = new BigInteger("1111");System.out.println(bigInteger);//解读://1. 在对BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符//2. 可以创建一个 要操作的 BigInteger 然后进行相应操作System.out.println(bigInteger.add(bigInteger1));System.out.println(bigInteger.subtract(bigInteger1));System.out.println(bigInteger.multiply(bigInteger1));System.out.println(bigInteger.divide(bigInteger1));//当编程中需要使用精度很高的小数,double不够用//可以使用 BigC类double d = 3.14159267777888899999999999;System.out.println(d); //只输出 3.141592677778889BigDecimal bigDecimal = new BigDecimal("3.14159267777888899999999999");BigDecimal bigDecimal1 = new BigDecimal("3.1");System.out.println(bigDecimal);//解读://1. 在对BigDecimal 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符//2. 可以创建一个 要操作的 BigDecimal 然后调用相应方法进行操作System.out.println(bigDecimal.add(bigDecimal1));System.out.println(bigDecimal.subtract(bigDecimal1));System.out.println(bigDecimal.multiply(bigDecimal1));// System.out.println(bigDecimal.divide(bigDecimal1)); //可能抛出ArithmeticException异常//解决方法 调用divide方法时指定精度 BigDecimal.ROUND_CEILING//如果有无限循环小数,就会保留被除数精度System.out.println(bigDecimal.divide(bigDecimal1, BigDecimal.ROUND_CEILING));}
九、日期类
9.1 第一代日期
- Date:精确到毫秒,代表特定的瞬间。
- SimpleDateFormat:格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化。 ```java package com.hspedu.date_;
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;
/**
- @author HarborGao
@version 1.0 */ public class Date01 { public static void main(String[] args) throws ParseException {
//解读://1. 获取当前系统时间//2. 这里的Date类 引用的是 java.util包//3. 默认输出的日期格式是国外的方式,因此通常需要对格式进行转换Date d1 = new Date(); //获取当前系统时间System.out.println("当前日期 " + d1);Date d2 = new Date(1632219604198l); //通过指定毫秒数得到时间System.out.println("当前日期 " + d2);System.out.println(d1.getTime()); //获取某个时间对应的毫秒数//解读//1. 创建 SimpleDateFormat 对象,可以指定相应格式//2. 这里的格式使用的字母是规定好的,参考模式字母表SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");String format = sdf.format(d1); //将日期转换成指定格式的字符串System.out.println(format);//解读://1. 可以把一个格式化的String 转成对应的 Date//2. 得到的Date 在输出时默认还是国外的格式,可以通过SimpleDateFormat转换//3. 在把String 转成 Date 时,字符串的格式需要和创建的SimpleDateFormat对象的格式一致,否则无法完成转换String s = "1996年01月01日 10:20:30 星期一";Date parse = sdf.parse(s);System.out.println("parse = " + sdf.format(parse));
} } ```
9.2 SimpleDateFormat 中的模式字母
| 字母 | 日期或时间元素 | 表示 | 示例 |
|---|---|---|---|
| G | Era 标志符 | Text | AD |
| y | 年 | Year | 1996; 96 |
| M | 年中的月份 | Month | July; Jul; 07 |
| w | 年中的周数 | Number | 27 |
| W | 月份中的周数 | Number | 2 |
| D | 年中的天数 | Number | 189 |
| d | 月份中的天数 | Number | 10 |
| F | 月份中的星期 | Number | 2 |
| E | 星期中的天数 | Text | Tuesday; Tue |
| a | Am/pm 标记 | Text | PM |
| H | 一天中的小时数(0-23) | Number | 0 |
| k | 一天中的小时数(1-24) | Number | 24 |
| K | am/pm 中的小时数(0-11) | Number | 0 |
| h | am/pm 中的小时数(1-12) | Number | 12 |
| m | 小时中的分钟数 | Number | 30 |
| s | 分钟中的秒数 | Number | 55 |
| S | 毫秒数 | Number | 978 |
| z | 时区 | General time zone | Pacific Standard Time; PST; GMT-08:00 |
| Z | 时区 | RFC 822 time zone | -0800 |
9.3 第二代日期类
- 第二代日期类,主要就是 Calender类(日历)。
- Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAYOF_MONTH、HOUR 等日历字段之间的转换提供了一些方法,并未操作日历字段(例如获得下星期的日期)提供了一些方法。 ```java package com.hspedu.date;
import java.util.Calendar;
/**
- @author HarborGao
@version 1.0 */ public class Calendar01 { public static void main(String[] args) {
//解读//1. Calendar 是一个抽象类,并且构造器是protected//2. 可以通过 getInstance() 来获取实例//3. 提供大量的方和字段给程序员Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由System.out.println(c);//获取日历对象的某个字段System.out.println("年:" + c.get(Calendar.YEAR));System.out.println("月:" + c.get(Calendar.MONTH) + 1);System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));System.out.println("小时:" + c.get(Calendar.HOUR));System.out.println("分钟:" + c.get(Calendar.MINUTE));System.out.println("秒:" + c.get(Calendar.SECOND));//Calendar 没有专门的格式化方法,需要程序员自己组合显示出来System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月" + (c.get(Calendar.DAY_OF_MONTH))+ "日" + (c.get(Calendar.HOUR)) + "时" + (c.get(Calendar.MINUTE)) + "分" + (c.get(Calendar.SECOND)) + "秒");
} } ```
9.4 第三代日期类
前面两代日期类的不足分析
jdk 1.0 中包含了一个java.util.Date类,但是它的大多数方法已经在 jdk 1.1 引入Calendar类之后被弃用了。
而Calendar 也存在问题是:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date 中的年份是从1900开始的,而月份都是从0开始
- 格式化:格式化只对 Date有用,Calendar则不行
- 此外,它们也不是线程安全的,不能处理闰秒等(每隔两天,多出1s)
9.5 第三代日期类常见方法(jdk8 加入)
- LocalDate(日期):只包含日期,可以获取日期字段
- LocaTime(时间):只包含时间,可以获取时间字段
- LocalDateTime(日期时间):包含日期+时间,可以获取日期和时间字段 ```java package com.hspedu.date_;
import java.time.LocalDateTime; import java.time.Year;
/**
- @author HarborGao
- @version 1.0
*/
public class Date03 {
public static void main(String[] args) {
} } ```//第三代日期//解读://1. 使用 now() 返回表示当前日期时间的对象LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now(); //LocalTime.now();System.out.println(ldt);String time = ldt.getYear() + "年" + ldt.getMonthValue() + "月" + ldt.getDayOfMonth() + "日 " + ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond();System.out.println(time);System.out.println(ldt.getMonth());
9.6 DateTimeFormatter 格式日期类
类似于SimpleDateFormat
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
//2. 使用DateTimeFormatterDateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");String format = dateTimeFormatter.format(ldt);System.out.println("格式化的日期:" + format);
9.7 第三代日期 - 时间戳 Instant
类似于 Date
提供了一系列和 Date 类转换的方式:
Instant -> Date:
Date date = Date.from(instant);
Date -> Instant:
Instant instant = date.toInstant();
9.8 第三代日期类更多方法
LocalDateTime 类
MonthDay 类:检查重复事件
是否是闰年
增加日期的某个部分
使用 plus 或者 minus 相关方法跳转日期
其他的方法参考API文档
十、章节练习
- 编程题
- 将字符串中指定的部分进行反转。比如”abcdef”反转为”aedcbf”
- 编写方法 public static String reverse(String str, int start, int end) 来搞定 ```java package com.hspedu.homework_.homework01;
/**
- @author HarborGao
@version 1.0 */ public class Homework01 { public static void main(String[] args) {
String src = "abcdef";
// String reverse = reverse(src, 0, 3); // System.out.println(reverse);
try {src = change(src,8,4);} catch (Exception e) {System.out.println(e.getMessage());return;}System.out.println(src);
} //方案一 public static String reverse(String str, int start, int end) {
char[] chars = str.toCharArray();char[] newChar = new char[chars.length];for (int i = 0,j = 0; i < chars.length; i++) {if (i < start || i > end) {newChar[i] = chars[i];} else {newChar[end - j] = chars[i];j++;}}return new String(newChar);
} //方案二 public static String change(String str, int start, int end) {
//对输入的参数校验//重要的编程技巧!!!//(1) 写出正确的情况//(2) 然后取反即可if (!(str != null && start >=0 && end > start && end < str.length())) {throw new RuntimeException("参数有误");}char[] chars = str.toCharArray();char temp = ' ';//交换辅助变量for (int i = start,j = end; i < j ; i++,j--) {temp = chars[i];chars[i] = chars[j];chars[j] = temp;}//使用chars 重新构建一个String 返回即可return new String(chars);
} } ```
- 编程题
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
要求:
- 用户名长度为2或3或4
- 密码的长度为6,要求全是数字 isDigital
- 邮箱中包含 @ 和 . 并且 @ 在 . 的前面 ```java package com.hspedu.homework_.homework02;
public class Register { public static void main(String[] args) { String name = “jas”; String password = “126456”; String email = “abc@163.com”; try { userRegister(name, password, email); System.out.println(“注册成功!”); } catch (Exception e) { System.out.println(e.getMessage()); } } /**
* 输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象* 要求:* (1) 用户名长度为2或3或4* (2) 密码的长度为6,要求全是数字 isDigital* (3) 邮箱中包含 @ 和 . 并且 @ 在 . 的前面** 思路分析:* (1) 先编写方法 userRegister(String name, String pwd, String email) {}* (2) 针对 输入的内容进行校验,如果发现有问题,就抛出异常,给出提示* (3) 单独的写一个方法,判断 密码是否全部都是数字字符 boolean*/public static void userRegister(String name, String pwd, String email) {//补充校验if (name == null || pwd == null || email == null) {throw new RuntimeException("参数不能为空");}//第一关int userLength = name.length();if(!(userLength >= 2 && userLength <= 4)) {throw new RuntimeException("用户名长度为2或3或4");}//第二关if (!(pwd.length() == 6 && isDigital(pwd))) {throw new RuntimeException("密码的长度为6,要求全是数字");}//第三关int i = email.indexOf('@');int j = email.indexOf('.');if (!(i > 0 && i < j)) {throw new RuntimeException("邮箱中包含 @ 和 . 并且 @ 在 . 的前面");}}public static boolean isDigital(String pwd) {char[] chars = pwd.toCharArray();for (int i = 0; i < chars.length; i++) {if (chars[i] < '0' || chars[i] > '9') {return false;}}return true;}
}
3. 编程题1. 编写Java程序,输入形式为:Han Shun Ping 的人名,以 Ping,Han.S 的形式打印出来。其中,.S 是中间单词的首字母。1. 例如输入 "Willian Jefferson Clinton",输出形式为:Clinton,Willian.J```javapackage com.hspedu.homework_.homework03;public class Homework03 {public static void main(String[] args) {String name = "Han Shun Ping";String name2 = "Willian Jefferson Clinton";try {reName(name);} catch (Exception e) {System.out.println(e.getMessage());}}public static void reName(String name) {if (name == null) {throw new RuntimeException("参数不能为空!");}String[] names = name.split(" ");if (names.length != 3) {throw new RuntimeException("传入的格式有误!");}String format = String.format("%s,%s.%c",names[2],names[0],names[1].toUpperCase().charAt(0));System.out.println(format);}}
- 编程题
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
package com.hspedu.homework_.homework04;public class Homework04 {public static void main(String[] args) {String n = "asf1654asfAFAF";countStr(n);}public static void countStr(String str) {if (str == null) {System.out.println("字符串不能为 null");return;}int countUpper = 0;int countLower = 0;int countNum = 0;for (int i = 0; i < str.length(); i++) {if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {countUpper++;} else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {countLower++;} else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {countNum++;}}String format = String.format("该字符串含有大写字母%d个,小写字母%d个,数字%d个",countUpper,countLower,countNum);System.out.println(format);}}
- 试写出下面程序的运行结果
已知Animal类有属性name, 可以通过有参构造为属性赋值
class Animal {String name;public Animal(String name) {this.name = name;}}//main方法String s1 = "hspedu";Animal a = new Animal(s1);Animal b = new Animal(s1);System.out.println(a == b); //falseSystem.out.println(a.equals(b)); //falseSystem.out.println(a.name == b.name); //trueString s4 = new String("hspedu");String s5 = "hspedu";System.out.println(s1 == s4); //falseSystem.out.println(s4 == s5); //falseString t1 = "hello" +s1;String t2 = "hellohspedu";System.out.println(t1.intern() == t2); //true
学习参考(致谢):
- B站 @程序员鱼皮 Java学习一条龙
- B站 @韩顺平 零基础30天学会Java
