一、包装类

1.1 包装类的分类

基本数据类型 包装类
boolean Boolean
char Character
byte Byte
short Short
long Long
int Integer
float Float
double Double
  1. 针对八种基本定义相应的引用类型——包装类
  2. 有了类的特点,就可以调用类中的方法

>> 继承体系图:
image.png
image.png
image.png

1.2 包装类和基本数据的转换

  1. jdk5 前的手动装箱和拆箱方式,装箱:基本类型 -> 包装类型 ,反之,拆箱

    1. //jdk5 之前:手动装箱和拆箱
    2. //手动装箱 int -> Integer
    3. int n1 = 100;
    4. Integer integer = new Integer(n1);
    5. Integer integer1 = Integer.valueOf(n1);
    6. //手动拆箱 Integer -> int
    7. int i = integer.intValue();
  2. jdk 以后(含 jdk5)的自动装箱和拆箱方式

    1. //jdk5 之后:自动装箱和拆箱
    2. //自动装箱 int -> Integer
    3. int n2 = 200;
    4. Integer integer2 = n2; //底层使用的仍然是 Integer.valueOf()
    5. //自动拆箱 Integer -> int
    6. int n3 = integer2;
  3. 自动装箱底层调用的是 valueOf 方法,比如:Integer.valueOf()

  4. 其他包装类的用法类似

⏱ 小练习

  1. 下面代码是否正确?
    Double d = 100d; //ok.自动装箱 Double.valueOf(100d);
    Float f = 1.5f; //ok.自动装箱 Float.valueOf(1.5f);

  2. 下面两段代码输出结果相同吗?各自输出什么?
    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类型 的相互转换

  1. public class WrapperVsString {
  2. public static void main(String[] args) {
  3. //包装类(Integer) -> String
  4. Integer i1 =100; //自动装箱
  5. String str1 = i1 + ""; //方式1
  6. String str2 = i1.toString(); //方式2
  7. String str3 = String.valueOf(i1); //方式3
  8. //String -> 包装类(Integer)
  9. Integer i2 = Integer.parseInt(str1); //返回的是int类型,自动装箱到Integer
  10. Integer i3 = new Integer(str1); //方式2
  11. }
  12. }

1.4 Integer类 和 Character类 的常用方法

  1. System.out.println(Integer.MIN_VALUE); //返回最小值
  2. System.out.println(Integer.MAX_VALUE); //返回最大值
  3. System.out.println(Character.isDigit('a')); //判断是不是数字
  4. System.out.println(Character.isLetter('a')); //判断是不是字母
  5. System.out.println(Character.isUpperCase('a')); //判断是不是大写
  6. System.out.println(Character.isLowerCase('a')); //判断是不是小写
  7. System.out.println(Character.isWhitespace('a')); //判断是不是空格
  8. System.out.println(Character.toUpperCase('a')); //转成大写
  9. 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);
}

小结:

  1. 形如:Integer m = 1; 虽然会自动装箱,底层还是调用了 valueOf()方法,但是根据装入的值不不同,如果装入的值在 -128 ~ 127 范围内,则不会创建对象,直接返回数值,否则创建一个新的对象返回。
  2. ==比较运算时,只要有一方为 int 类型,则比较的是数值是否相等,而不是地址是否相同

二、String 类

2.1 String类的理解和创建对象

  1. String 对象用于保存字符串,也就是一组字符序列
  2. 字符串常量对象是用双引号括起来的字符序列。例如:”你好”、”12.98”、”boy”等
  3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
  4. String类较常用构造器(其他看手册):
    1. String s1 = new String();
    2. String s2 = new String(String original);
    3. String s3 = new String(char[] a);
    4. String s4 = new String(char[] a,int startIndex,int count);
    5. String s5 = new String(byte[] b);

image.png

  1. String类 实现了接口 Serializable【String可以串行化:可以在网络传输】
  2. String类 实现了接口 Comparable【String对象可以互相比较】
  3. String 是 final 类,不能被其他类继承
  4. String 有属性 private final char value[]; 用于存放字符串内容
  5. 一定要注意:value 是一个 final类型,不可以修改【指向的地址】
    1. final char[] value = {'a','b','c'};
    2. value[1] = 'D'; //可以改变数组内的值
    3. char[] v2 = {'t','o','m'};
    4. value = v2; //错误,final类型不能改变地址指向

2.2 创建 String对象的两种方式

  1. 方式一:直接赋值 String s = “java”;
  2. 方式二:调用构造器 String s = new String(“java”);

区别:

  1. 方式一:先从常量池查看是否有”java”数据空间,如果有,直接访问;如果没有则创建,然后指向。s 最后指向的是常量池的空间地址。
  2. 方式二:先在堆中创建空间,里面维护了 value 属性,指向常量池的 “java” 空间。如果常量池没有 “java”,重新创建,如果有,直接通过 value 指向。最终指向的是堆中的空间地址。
  3. 两种方式的内存分布图

常用类 - 图5
常用类 - 图6
小练习

  1. 判断下面代码输出结果:

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);

  1. 判断下面代码的输出结果:

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对象所指向常量池空间元素的地址

  1. 测试题

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);

  1. 测试题

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

  1. // 验证"java"在参与 ==运算 时返回的就是在常量池中的地址
  2. String a = "java";
  3. System.out.println(a.hashCode());
  4. System.out.println("java".hashCode());

2.3 字符串的特性

  1. String 是一个 final类,代表不可变的字符序列
  2. 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。

例题:以下语句创建了几个对象?(2个)
String s1 = “hello”;
s1 = “haha”;

面试题1
String a = “hello” + “abc”;
创建了几个对象?(1个)
解析:编译器在底层会自动将+号两边的字符串拼接成一个字符串的优化,会判断创建的常量池对象,是否有引用指向。

面试题2
String a = “hello”;
String b = “abc”;
String c = a + b;
创建了几个对象?(3个)
解读:底层实现过程

  1. 先创建一个 StringBuilder sb = StringBuilder()
  2. 执行 sb.append(“hello”)
  3. 执行 sb.append(“abc”)
  4. 执行 String c = sb.toString()
  5. 最后 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 分割字符串,对于某些分割字符,我们需要转义字符 \
  1. public class StringMethod {
  2. public static void main(String[] args) {
  3. String a = "java";
  4. String b = "JAVA";
  5. System.out.println(a.equals(b));
  6. System.out.println(a.equalsIgnoreCase(b));
  7. System.out.println(a.length());
  8. System.out.println(a.charAt(2));
  9. System.out.println(a.indexOf('a'));
  10. System.out.println(a.lastIndexOf('a'));
  11. String c = "i am learning java!";
  12. String d = c.substring(2); //一个参数:从索引为2开始,截取到字符串尾
  13. System.out.println(d);
  14. String e = c.substring(2,6); //两个参数:从索引2开始,截取至索引为(6-1)
  15. //辅助记忆: 左闭右开 [2,6)
  16. System.out.println(e);
  17. System.out.println(" j a v a ");
  18. System.out.println(" j a v a ".trim()); //去首尾空格,不去中间空格
  19. System.out.println(a.toUpperCase()); //全部转为大写
  20. System.out.println(b.toLowerCase()); //全部转为小写
  21. System.out.println(a.concat(b)); //拼接两字符串
  22. String g = "贾宝玉 and 林黛玉 林黛玉 林黛玉";
  23. System.out.println(g.replace("林黛玉","薛宝钗")); //替代字符串内容
  24. String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
  25. String[] split = poem.split(","); //以,为标准,对字符串进行分割,返回的是字符串数组
  26. String fileA = "E:\\aaa\\bbb";
  27. String[] split2 = fileA.split("\\|");
  28. String[] split3 = fileA.split("\\\\");
  29. for (int i = 0; i < split.length; i++) {
  30. System.out.println(split[i]);
  31. }
  32. for (int i = 0; i < split2.length; i++) {
  33. System.out.println(split2[i]);
  34. }
  35. for (int i = 0; i < split3.length; i++) {
  36. System.out.println(split3[i]);
  37. }
  38. String bj = "jchk";
  39. //比较过程:
  40. // (1) 先获取两字符串长度,取最小值min
  41. // (2) 从索引为0开始依次比较两字符串,若出现不同值则返回(前一个字符对应编码值 - 后一个字符对应编码值)的结果
  42. // (3) 若在比较到(min-1)索引都相同,则返回(前一个字符串长度 - 后一个字符串长度)的结果
  43. // (4) 两字符串相等 返回0
  44. System.out.println(a.compareTo(bj));
  45. char[] chars = c.toCharArray(); //将字符串转换成字符数组
  46. for (int i = 0; i < chars.length; i++) {
  47. System.out.println(chars[i]);
  48. }
  49. // format 格式化字符串
  50. /* 占位符有
  51. * %s 字符串 %c 字符 %d 整型 %.2f 浮点型
  52. *
  53. */
  54. String name = "john";
  55. int age = 10;
  56. double score = 98.3 / 3;
  57. char gender = '男';
  58. String info = "我的名字是" + name + " 年龄是" + age + ",成绩是" + score + " 性别是" + gender + "。希望大家喜欢我!";
  59. System.out.println(info);
  60. String information = "我的名字是%s 年龄是%d,成绩是%.2f 性别是%c。希望大家喜欢我!";
  61. String info2 = String.format(information,name,age,score,gender);
  62. System.out.println(info2);
  63. }
  64. }

三、StringBuffer 类

3.1 基本介绍

java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
很多方法与 String 相同,但 StringBuffer 是可变长度的
StringBuffer 是一个容器

3.2 StringBuffer 特点

  1. StringBuffer 是 final 类,不能被其他类继承
  2. 实现了接口 Serializable【可以保存到文件,或网络传输】
  3. 继承了抽象类 AbstractStringBuilder
  4. AbstractStringBuilder 有属性 char[] value 不是 final 类型,用于存放字符串内容,存放在堆中
  5. 因为StringBuffer 字符内容是存在 char[] value,所以发生变化(增加/删除)不用每次都更换地址(即不是每次都创建新对象),所以效率高于String

3.3 String VS StringBuffer

  1. String 保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低
  2. 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 获取字符串长度
  1. public class StringBufferMethod {
  2. public static void main(String[] args) {
  3. StringBuffer sbr = new StringBuffer("hello");
  4. sbr.append(','); //增加
  5. sbr.append("张三丰").append(100).append(true).append(10.5);
  6. System.out.println(sbr);
  7. sbr.delete(5,9); //删除 [5,9) 左闭右开 删除索引5-8的字符
  8. System.out.println(sbr);
  9. sbr.replace(0,5,"java"); //替换索引0-4的字符
  10. System.out.println(sbr);
  11. System.out.println(sbr.indexOf("10"));
  12. sbr.insert(4,"hello"); //在索引3和4之间插入字符内容
  13. System.out.println(sbr);
  14. System.out.println(sbr.length());
  15. }
  16. }

练习题1
看下面代码输出什么?为什么?

  1. public class StringBufferExercise01 {
  2. public static void main(String[] args) {
  3. String str = null;
  4. StringBuffer sb = new StringBuffer();
  5. sb.append(str);
  6. System.out.println(sb.length());
  7. System.out.println(sb);
  8. StringBuffer sb1 = new StringBuffer(str);
  9. System.out.println(sb1);
  10. }
  11. }

知识点:StringBuffer使用 append() 方法时,如果传入的是 null,就会将null 转换成 “null”字符串传入,
但是构造器中传入 null 的 String对象,就会抛出空指针异常,原因是底层代码中的 super(str.length() + 16)。

练习题2
输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成:
商品名 商品价格
手机 123,456.59
要求:价格的小数点前面每三位用逗号隔开

  1. public class StringBufferExercise02 {
  2. public static void main(String[] args) {
  3. StringBuffer name = new StringBuffer("手机");
  4. StringBuffer price = new StringBuffer("1123564.59");
  5. int point = price.lastIndexOf(".");
  6. for (int i = point - 3; i > 0 ; i -= 3) {
  7. price.insert(i,",");
  8. }
  9. System.out.println("商品名\t商品价格\n" + name + "\t" + price);
  10. }
  11. }

四、StringBuilder 类

4.1 基本介绍

  1. 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer 要快。

  2. 在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。

4.2 StringBuilder 特点

  1. StringBuilder 是final 类,不能被其他类继承
  2. 继承了 AbstractStringBuilder,属性 char[] value,内容存到 value
  3. 实现了接口 Serializable【可以保存到文件,或网络传输】,序列化【可以保存类型和数据本身】
  4. StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字的处理,因此在单线程的情况下使用

4.2 StringBuilder 常见方法

StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer一样。

4.3 String、StringBuilder、StringBuffer 的比较

  1. StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样。
  2. String:不可变字符序列,效率低,但是复用性高。
  3. StringBuffer:可变字符序列,效率较高(增删)、线程安全。
  4. StringBuilder:可变字符序列,效率最高,线程不安全。
  5. String 使用注意:
    1. String s = “a”; //创建了一个字符串
    2. s += “b”; //实际上原来的 “a”字符串对象已经丢弃了,现在又产生一个字符串s + “b”(也就是”ab”)。如果多次执行这些改变字符串的内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能
    3. 结论:如果我们对String 做大量修改,不要使用String

String、StringBuilder、StringBuffer 的效率测试

  1. public class StringBuilder01 {
  2. public static void main(String[] args) {
  3. long startTime = 0L;
  4. long endTime = 0L;
  5. startTime = System.currentTimeMillis();
  6. StringBuffer buffer = new StringBuffer("");
  7. for (int i = 0; i < 80000; i++) {
  8. buffer.append(String.valueOf(i));
  9. }
  10. endTime = System.currentTimeMillis();
  11. System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
  12. startTime = System.currentTimeMillis();
  13. StringBuilder builder = new StringBuilder("");
  14. for (int i = 0; i < 80000; i++) {
  15. builder.append(String.valueOf(i));
  16. }
  17. endTime = System.currentTimeMillis();
  18. System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
  19. startTime = System.currentTimeMillis();
  20. String text = "";
  21. for (int i = 0; i < 80000; i++) {
  22. text = text + i;
  23. }
  24. endTime = System.currentTimeMillis();
  25. System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
  26. }
  27. }

String、StringBuilder、StringBuffer 的选择
使用原则,结论:

  1. 如果字符串存在大量的修改操作,一般使用 StringBuffer 或者 StringBuilder
  2. 如果字符串存在大量的修改操作,并且在单线程的情况,使用 StringBuilder
  3. 如果字符串存在大量的修改操作,并且在多线程的情况,使用 StringBuffer
  4. 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等

五、Math 类

5.1 基本介绍

Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

5.2 Math类常见方法(静态方法)

method 作用
abs 取绝对值
pow 求幂
ceil 向上取整
floor 向下取整
round 四舍五入
sqrt 求开方
random 获取随机数
max 取最大值
min 取最小值
  1. public class MathMethod {
  2. public static void main(String[] args) {
  3. //看看Math常用的方法(静态方法)
  4. //1.abs 绝对值
  5. int abs = Math.abs(-9);
  6. System.out.println(abs);
  7. //2.pow 求幂
  8. double pow = Math.pow(2,4);
  9. System.out.println(pow);
  10. //3.ceil 向上取整 返回大于等于该参数的最小整数
  11. double ceil = Math.ceil(-3.0001);
  12. System.out.println(ceil);
  13. //4.floor 向下取整 返回小于等于该参数的最大整数
  14. double floor = Math.floor(-4.999);
  15. System.out.println(floor);
  16. //5.round 四舍五入 Math.floor(该参数+0.5)
  17. double round = Math.round(-5.501);
  18. System.out.println(round);
  19. //6.sqrt 开平方
  20. double sqrt = Math.sqrt(9.0);
  21. System.out.println(sqrt);
  22. //7.0 random 求随机数
  23. // 获取 a - b 之间的一个随机整数,a,b均为整数
  24. int a = 2;
  25. int b = 7;
  26. double x = 0;
  27. for (int i = 0; i < 50; i++) {
  28. x = (int)(Math.random() * (b+1-a) + a);
  29. System.out.println(x);
  30. }
  31. }
  32. }

六、Arrays类

6.1 基本介绍

Arrays 里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。

6.2 Arrays 常见方法

method 作用
sort 自然排序,从小到大
toString 转成字符串
binarySearch 二分查找
copyOf 数组拷贝
fill 数组填充
equals 数组比较
asList 将一组值,转换成list
  1. package com.hspedu.arrays_;
  2. import java.util.Arrays;
  3. import java.util.Comparator;
  4. import java.util.List;
  5. /**
  6. * @author HarborGao
  7. * @version 1.0
  8. */
  9. public class Arrays01 {
  10. public static void main(String[] args) {
  11. Integer arr[] = {1, 5, 10, 8, 6, 22};
  12. System.out.println(Arrays.toString(arr));
  13. Arrays.sort(arr, 0, 4); //指定索引范围内自然排序
  14. System.out.println(Arrays.toString(arr));
  15. Arrays.sort(arr); //自然排序 从小到大
  16. System.out.println(Arrays.toString(arr));
  17. int find = Arrays.binarySearch(arr,11);
  18. System.out.println(find);
  19. // 排序
  20. //1. 可以直接使用冒泡排序,也可以直接使用Arrays提供的sort方法排序
  21. //2. 因为数组是引用类型,索引进行sort排序后,会直接影响到实参 arr
  22. //3. sort 重载的,也可以通过传入一个接口 Comparator 实现定制排序
  23. //4. 调用定制排序时,传入两个参数 (1) 排序数组 arr
  24. // (2) 实现了Comparator接口的匿名内部类,要求实现 compare 方法
  25. //5. 这里体现了接口编程的一种方式
  26. Arrays.sort(arr, new Comparator() {
  27. @Override
  28. public int compare(Object o1, Object o2) {
  29. Integer i1 = (Integer) o1;
  30. Integer i2 = (Integer) o2;
  31. return i2 - i1;
  32. }
  33. });
  34. System.out.println(Arrays.toString(arr));
  35. System.out.println("==自定义排序==");
  36. int[] arr2 = {1, -1, 5, 3, 8, 10};
  37. // bubble01(arr2);
  38. bubble02(arr2, new Comparator() {
  39. @Override
  40. public int compare(Object o1, Object o2) {
  41. int i1 = (Integer) o1;
  42. int i2 = (Integer) o2;
  43. return i2 - i1;
  44. }
  45. });
  46. System.out.println(Arrays.toString(arr2));
  47. Integer arr3[] = {10, 5, 2, 1};
  48. int index = Arrays.binarySearch(arr3,1, new Comparator(){
  49. @Override
  50. public int compare(Object o1, Object o2) {
  51. Integer n1 = (Integer) o1;
  52. Integer n2 = (Integer) o2;
  53. return n2 - n1;
  54. }
  55. });
  56. System.out.println(index);
  57. //copyOf 数组拷贝
  58. Integer[] newArr = Arrays.copyOf(arr,arr.length - 1 );
  59. System.out.println(Arrays.toString(newArr));
  60. //fill 数组填充
  61. Integer[] num = {1,9,3};
  62. Arrays.fill(num,99); //用99替换数组所有值
  63. System.out.println(Arrays.toString(num));
  64. //equals 数组比较
  65. Integer[] num2 = {99,99,99};
  66. System.out.println(Arrays.equals(num,num2));
  67. //asList 将一组值,转换成list
  68. //解读:
  69. //1. asList方法,会将(2,3,5,7,9)数据转成一个List集合
  70. //2. 返回的 asList 编译类型 List(接口)
  71. //3. asList 运行类型 java.util.Arrays#ArraysList,是Arrays类的静态内部类
  72. List asList = Arrays.asList(2,3,5,7,9);
  73. System.out.println("asList = " + asList);
  74. }
  75. //冒泡排序
  76. public static void bubble01(int[] arr) {
  77. int temp = 0;
  78. for (int i = 0; i < arr.length; i++) {
  79. for (int j = 0; j < arr.length - 1 - i; j++) {
  80. if (arr[j] > arr[j + 1]) {
  81. temp = arr[j];
  82. arr[j] = arr[j + 1];
  83. arr[j + 1] = temp;
  84. }
  85. }
  86. }
  87. }
  88. //冒泡排序 + 定制
  89. public static void bubble02(int[] arr, Comparator c) {
  90. int temp = 0;
  91. for (int i = 0; i < arr.length; i++) {
  92. for (int j = 0; j < arr.length - 1 - i; j++) {
  93. if (c.compare(arr[j], arr[j + 1]) > 0) {
  94. temp = arr[j];
  95. arr[j] = arr[j + 1];
  96. arr[j + 1] = temp;
  97. }
  98. }
  99. }
  100. }
  101. }
  102. /*
  103. 使用binarySearch时
  104. 1. 如果传入两个参数,第一个参数是数组,第二个参数是要查找的值,数组必须是有序递增的
  105. 2. 如果传入三个参数,第一个参数是数组,第二个参数是要查找的值,第三个参数是匿名内部类Comparator
  106. 数组必须是有序(递增或递减)的,匿名内部类重写compare方法用于定制查询
  107. 3. 如果传入四个参数,第一个参数是数组,第二个参数是起始索引,第三个是结束索引,第四个是要查找的值
  108. 用于在指定索引范围内查找,要求数组必须是有序递增的
  109. 3. 查找策略依据以下底层源码,如果找不到,返回负数,代表的是该值应该在的位置
  110. public static int binarySearch(int[] a, int key) {
  111. return binarySearch0(a, 0, a.length, key);
  112. }
  113. private static int binarySearch0(int[] a, int fromIndex, int toIndex,
  114. int key) {
  115. int low = fromIndex; // 0
  116. int high = toIndex - 1; // a.length - 1
  117. while (low <= high) {
  118. int mid = (low + high) >>> 1;
  119. int midVal = a[mid];
  120. if (midVal < key)
  121. low = mid + 1;
  122. else if (midVal > key)
  123. high = mid - 1;
  124. else
  125. return mid; // key found
  126. }
  127. return -(low + 1); // key not found.
  128. }
  129. */

6.3 小练习

案例:自定义Book类,里面包含 name 和 price,。要求使用两种方式排序,分别按price 排序(从大到小)和按书名排序(从长到短)。 Book[] books = 4本书对象。
其中一种使用前面学习过的传递,实现Comparator接口匿名内部类,也称为定制排序。

  1. package com.hspedu.arrays_;
  2. import java.util.Arrays;
  3. import java.util.Comparator;
  4. /**
  5. * @author HarborGao
  6. * @version 1.0
  7. */
  8. public class ArraysExercise01 {
  9. public static void main(String[] args) {
  10. Book[] books = new Book[4];
  11. books[0] = new Book("红楼梦~~~~", 100);
  12. books[1] = new Book("金瓶梅~", 90);
  13. books[2] = new Book("青年文摘~", 5);
  14. books[3] = new Book("java从入门到放弃", 300);
  15. //方法一 sort方法
  16. // Arrays.sort(books, new Comparator() {
  17. // @Override
  18. // public int compare(Object o1, Object o2) {
  19. // Book book1 = (Book) o1;
  20. // Book book2 = (Book) o2;
  21. // double res = book2.getPrice() - book1.getPrice();
  22. // if (res > 0) {
  23. // return 1;
  24. // } else if (res < 0) {
  25. // return -1;
  26. // } else {
  27. // return 0;
  28. // }
  29. // }
  30. // });
  31. // System.out.println(Arrays.toString(books));
  32. //方法二 冒泡排序
  33. for (int i = 0; i < books.length; i++) {
  34. for (int j = 0; j < books.length - i - 1; j++) {
  35. if (books[j].getName().length() - books[j + 1].getName().length() < 0) {
  36. Book temp = books[j];
  37. books[j] = books[j + 1];
  38. books[j + 1] = temp;
  39. }
  40. }
  41. }
  42. System.out.println(Arrays.toString(books));
  43. }
  44. }
  45. class Book {
  46. private String name;
  47. private double price;
  48. public Book(String name, double price) {
  49. this.name = name;
  50. this.price = price;
  51. }
  52. public String getName() {
  53. return name;
  54. }
  55. public void setName(String name) {
  56. this.name = name;
  57. }
  58. public double getPrice() {
  59. return price;
  60. }
  61. public void setPrice(double price) {
  62. this.price = price;
  63. }
  64. @Override
  65. public String toString() {
  66. return "Book{" +
  67. "name='" + name + '\'' +
  68. ", price=" + price +
  69. '}';
  70. }
  71. }

七、System 类

7.1 System类常见方法

method 作用
exit 退出
arraycopy 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf
currentTimeMillis 返回当前时间距离1970-1-1的毫秒数
gc 运行垃圾回收机制

八、BigInteger 和 BigDecimal 类

8.1 应用场景

  1. BigInteger 适合保存比较大的整型
  2. BigDecimal 适合保存精度更高的浮点型

8.2 BigInteger 和 BigDecimal 类常见方法

method 作用
add
subtract
multiply
divide
  1. public static void main(String[] args) {
  2. //当编程中需要使用很大的整数,long不够用
  3. //可以使用 BigInteger类
  4. // long l = 16546546464646464159999l;
  5. BigInteger bigInteger = new BigInteger("16546546464646464159999");
  6. BigInteger bigInteger1 = new BigInteger("1111");
  7. System.out.println(bigInteger);
  8. //解读:
  9. //1. 在对BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符
  10. //2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
  11. System.out.println(bigInteger.add(bigInteger1));
  12. System.out.println(bigInteger.subtract(bigInteger1));
  13. System.out.println(bigInteger.multiply(bigInteger1));
  14. System.out.println(bigInteger.divide(bigInteger1));
  15. //当编程中需要使用精度很高的小数,double不够用
  16. //可以使用 BigC类
  17. double d = 3.14159267777888899999999999;
  18. System.out.println(d); //只输出 3.141592677778889
  19. BigDecimal bigDecimal = new BigDecimal("3.14159267777888899999999999");
  20. BigDecimal bigDecimal1 = new BigDecimal("3.1");
  21. System.out.println(bigDecimal);
  22. //解读:
  23. //1. 在对BigDecimal 进行加减乘除的时候,需要使用对应的方法,不能直接使用+-*/运算符
  24. //2. 可以创建一个 要操作的 BigDecimal 然后调用相应方法进行操作
  25. System.out.println(bigDecimal.add(bigDecimal1));
  26. System.out.println(bigDecimal.subtract(bigDecimal1));
  27. System.out.println(bigDecimal.multiply(bigDecimal1));
  28. // System.out.println(bigDecimal.divide(bigDecimal1)); //可能抛出ArithmeticException异常
  29. //解决方法 调用divide方法时指定精度 BigDecimal.ROUND_CEILING
  30. //如果有无限循环小数,就会保留被除数精度
  31. System.out.println(bigDecimal.divide(bigDecimal1, BigDecimal.ROUND_CEILING));
  32. }

九、日期类

9.1 第一代日期

  1. Date:精确到毫秒,代表特定的瞬间。
  2. 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. //1. 获取当前系统时间
    3. //2. 这里的Date类 引用的是 java.util包
    4. //3. 默认输出的日期格式是国外的方式,因此通常需要对格式进行转换
    5. Date d1 = new Date(); //获取当前系统时间
    6. System.out.println("当前日期 " + d1);
    7. Date d2 = new Date(1632219604198l); //通过指定毫秒数得到时间
    8. System.out.println("当前日期 " + d2);
    9. System.out.println(d1.getTime()); //获取某个时间对应的毫秒数
    10. //解读
    11. //1. 创建 SimpleDateFormat 对象,可以指定相应格式
    12. //2. 这里的格式使用的字母是规定好的,参考模式字母表
    13. SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
    14. String format = sdf.format(d1); //将日期转换成指定格式的字符串
    15. System.out.println(format);
    16. //解读:
    17. //1. 可以把一个格式化的String 转成对应的 Date
    18. //2. 得到的Date 在输出时默认还是国外的格式,可以通过SimpleDateFormat转换
    19. //3. 在把String 转成 Date 时,字符串的格式需要和创建的SimpleDateFormat对象的格式一致,否则无法完成转换
    20. String s = "1996年01月01日 10:20:30 星期一";
    21. Date parse = sdf.parse(s);
    22. 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 第二代日期类

  1. 第二代日期类,主要就是 Calender类(日历)。
  2. 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. //解读
    2. //1. Calendar 是一个抽象类,并且构造器是protected
    3. //2. 可以通过 getInstance() 来获取实例
    4. //3. 提供大量的方和字段给程序员
    5. Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
    6. System.out.println(c);
    7. //获取日历对象的某个字段
    8. System.out.println("年:" + c.get(Calendar.YEAR));
    9. System.out.println("月:" + c.get(Calendar.MONTH) + 1);
    10. System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
    11. System.out.println("小时:" + c.get(Calendar.HOUR));
    12. System.out.println("分钟:" + c.get(Calendar.MINUTE));
    13. System.out.println("秒:" + c.get(Calendar.SECOND));
    14. //Calendar 没有专门的格式化方法,需要程序员自己组合显示出来
    15. System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月" + (c.get(Calendar.DAY_OF_MONTH))
    16. + "日" + (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 也存在问题是:

  1. 可变性:像日期和时间这样的类应该是不可变的
  2. 偏移性:Date 中的年份是从1900开始的,而月份都是从0开始
  3. 格式化:格式化只对 Date有用,Calendar则不行
  4. 此外,它们也不是线程安全的,不能处理闰秒等(每隔两天,多出1s)

9.5 第三代日期类常见方法(jdk8 加入)

  1. LocalDate(日期):只包含日期,可以获取日期字段
  2. LocaTime(时间):只包含时间,可以获取时间字段
  3. 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. //第三代日期
    2. //解读:
    3. //1. 使用 now() 返回表示当前日期时间的对象
    4. LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now(); //LocalTime.now();
    5. System.out.println(ldt);
    6. String time = ldt.getYear() + "年" + ldt.getMonthValue() + "月" + ldt.getDayOfMonth() + "日 " + ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond();
    7. System.out.println(time);
    8. System.out.println(ldt.getMonth());
    } } ```

9.6 DateTimeFormatter 格式日期类

类似于SimpleDateFormat
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
image.png

  1. //2. 使用DateTimeFormatter
  2. DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
  3. String format = dateTimeFormatter.format(ldt);
  4. 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文档

十、章节练习

  1. 编程题
    1. 将字符串中指定的部分进行反转。比如”abcdef”反转为”aedcbf”
    2. 编写方法 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) {

    1. String src = "abcdef";

    // String reverse = reverse(src, 0, 3); // System.out.println(reverse);

    1. try {
    2. src = change(src,8,4);
    3. } catch (Exception e) {
    4. System.out.println(e.getMessage());
    5. return;
    6. }
    7. System.out.println(src);

    } //方案一 public static String reverse(String str, int start, int end) {

    1. char[] chars = str.toCharArray();
    2. char[] newChar = new char[chars.length];
    3. for (int i = 0,j = 0; i < chars.length; i++) {
    4. if (i < start || i > end) {
    5. newChar[i] = chars[i];
    6. } else {
    7. newChar[end - j] = chars[i];
    8. j++;
    9. }
    10. }
    11. return new String(newChar);

    } //方案二 public static String change(String str, int start, int end) {

    1. //对输入的参数校验
    2. //重要的编程技巧!!!
    3. //(1) 写出正确的情况
    4. //(2) 然后取反即可
    5. if (!(str != null && start >=0 && end > start && end < str.length())) {
    6. throw new RuntimeException("参数有误");
    7. }
    8. char[] chars = str.toCharArray();
    9. char temp = ' ';//交换辅助变量
    10. for (int i = start,j = end; i < j ; i++,j--) {
    11. temp = chars[i];
    12. chars[i] = chars[j];
    13. chars[j] = temp;
    14. }
    15. //使用chars 重新构建一个String 返回即可
    16. return new String(chars);

    } } ```

  1. 编程题

输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
要求:

  1. 用户名长度为2或3或4
  2. 密码的长度为6,要求全是数字 isDigital
  3. 邮箱中包含 @ 和 . 并且 @ 在 . 的前面 ```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. * (1) 用户名长度为234
  4. * (2) 密码的长度为6,要求全是数字 isDigital
  5. * (3) 邮箱中包含 @ . 并且 @ . 的前面
  6. *
  7. * 思路分析:
  8. * (1) 先编写方法 userRegister(String name, String pwd, String email) {}
  9. * (2) 针对 输入的内容进行校验,如果发现有问题,就抛出异常,给出提示
  10. * (3) 单独的写一个方法,判断 密码是否全部都是数字字符 boolean
  11. */
  12. public static void userRegister(String name, String pwd, String email) {
  13. //补充校验
  14. if (name == null || pwd == null || email == null) {
  15. throw new RuntimeException("参数不能为空");
  16. }
  17. //第一关
  18. int userLength = name.length();
  19. if(!(userLength >= 2 && userLength <= 4)) {
  20. throw new RuntimeException("用户名长度为2或3或4");
  21. }
  22. //第二关
  23. if (!(pwd.length() == 6 && isDigital(pwd))) {
  24. throw new RuntimeException("密码的长度为6,要求全是数字");
  25. }
  26. //第三关
  27. int i = email.indexOf('@');
  28. int j = email.indexOf('.');
  29. if (!(i > 0 && i < j)) {
  30. throw new RuntimeException("邮箱中包含 @ 和 . 并且 @ 在 . 的前面");
  31. }
  32. }
  33. public static boolean isDigital(String pwd) {
  34. char[] chars = pwd.toCharArray();
  35. for (int i = 0; i < chars.length; i++) {
  36. if (chars[i] < '0' || chars[i] > '9') {
  37. return false;
  38. }
  39. }
  40. return true;
  41. }

}

  1. 3. 编程题
  2. 1. 编写Java程序,输入形式为:Han Shun Ping 的人名,以 Ping,Han.S 的形式打印出来。其中,.S 是中间单词的首字母。
  3. 1. 例如输入 "Willian Jefferson Clinton",输出形式为:Clinton,Willian.J
  4. ```java
  5. package com.hspedu.homework_.homework03;
  6. public class Homework03 {
  7. public static void main(String[] args) {
  8. String name = "Han Shun Ping";
  9. String name2 = "Willian Jefferson Clinton";
  10. try {
  11. reName(name);
  12. } catch (Exception e) {
  13. System.out.println(e.getMessage());
  14. }
  15. }
  16. public static void reName(String name) {
  17. if (name == null) {
  18. throw new RuntimeException("参数不能为空!");
  19. }
  20. String[] names = name.split(" ");
  21. if (names.length != 3) {
  22. throw new RuntimeException("传入的格式有误!");
  23. }
  24. String format = String.format("%s,%s.%c",names[2],names[0],names[1].toUpperCase().charAt(0));
  25. System.out.println(format);
  26. }
  27. }
  1. 编程题

输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字

  1. package com.hspedu.homework_.homework04;
  2. public class Homework04 {
  3. public static void main(String[] args) {
  4. String n = "asf1654asfAFAF";
  5. countStr(n);
  6. }
  7. public static void countStr(String str) {
  8. if (str == null) {
  9. System.out.println("字符串不能为 null");
  10. return;
  11. }
  12. int countUpper = 0;
  13. int countLower = 0;
  14. int countNum = 0;
  15. for (int i = 0; i < str.length(); i++) {
  16. if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
  17. countUpper++;
  18. } else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
  19. countLower++;
  20. } else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
  21. countNum++;
  22. }
  23. }
  24. String format = String.format("该字符串含有大写字母%d个,小写字母%d个,数字%d个",countUpper,countLower,countNum);
  25. System.out.println(format);
  26. }
  27. }
  1. 试写出下面程序的运行结果

已知Animal类有属性name, 可以通过有参构造为属性赋值

  1. class Animal {
  2. String name;
  3. public Animal(String name) {
  4. this.name = name;
  5. }
  6. }
  7. //main方法
  8. String s1 = "hspedu";
  9. Animal a = new Animal(s1);
  10. Animal b = new Animal(s1);
  11. System.out.println(a == b); //false
  12. System.out.println(a.equals(b)); //false
  13. System.out.println(a.name == b.name); //true
  14. String s4 = new String("hspedu");
  15. String s5 = "hspedu";
  16. System.out.println(s1 == s4); //false
  17. System.out.println(s4 == s5); //false
  18. String t1 = "hello" +s1;
  19. String t2 = "hellohspedu";
  20. System.out.println(t1.intern() == t2); //true

学习参考(致谢):

  1. B站 @程序员鱼皮 Java学习一条龙
  2. B站 @韩顺平 零基础30天学会Java