抽象类

抽象类的由来:

回顾昨天写的动物类代码, 我们在其中写了1个eat()方法, 方法中有一句”废话”: 动物会吃.不同的动物吃的内容是不一样的, 所以这句话写了也没有意义, 我们就思考, 能不能删掉呢?这样的方法就叫: 抽象方法, 有抽象方法的类, 就叫抽象类, Java中, 抽象用abstract表示.

抽象类的特点:

  1. Java中, 抽象用 abstract关键字表示.
  2. 有抽象方法的类一定是抽象类(或者接口), 但是抽象类中不一定有抽象方法.
  3. 抽象类不能直接实例化.
    问: 那抽象类怎么实例化呢?
    答: 通过 抽象类多态 实现, 即: 创建该抽象类的子类对象即可.
  4. 抽象类的子类.
    如果是普通类: 则必须重写该抽象类中所有的抽象方法.
    如果是抽象类: 则可以不用重写父类中的抽象方法.

抽象类的成员特点: (即, 抽象类中能写啥, 不能写啥.)

专业版: 变量, 常量, 构造方法, 非静态方法, 静态方法, 抽象方法.
简单记忆: 抽象类比普通类多一种抽象方法, 而且还可以不写.

问: 抽象类中的 抽象方法 和 非抽象方法有什么意义?

抽象方法: 强制要求子类必须完成某些操作.
非抽象方法: 让子类继承, 提高代码的复用性.

快捷键:

alt + enter(回车)

面向对象接口

接口的由来

我们知道, 抽象类中不仅可以写抽象方法, 还可以写变量, 常量, 构造方法, 静态方法, 非抽象方法等, 所以抽象类相对 “不纯粹”,
而且, 子类可以通过继承的方式从父类继承 除父构造方法外, 所有的公共内容(public修饰的), 这种方式, 耦合性比较强, 于是,
就出现了接口, 就是用来: 降低耦合性的.

举例

问: 假设Animal(动物类), 有子类Cat(猫类), Dog(狗类), 部分的猫, 经过了训练, 学会了跳高, 请问: 跳高的功能应该写到哪里?
答:
写到Animal类? 这就意味着 所有的 动物 都会跳高, 不合适.
写到Cat类? 这就意味着 所有的 猫 都会跳高, 不合适.
写到JumpCat类中? 可以, 但是不推荐, 万一其它的动物经过训练, 也学会了跳高呢? 不方便集中管理.
推荐: 定义1个接口, 里边有跳高的功能, 谁会跳高, 谁实现这个接口即可.

接口的特点

  1. Java中, 接口用 interface关键字表示, 类与接口之间是实现关系,用 implements修饰.
  2. 有抽象方法的类一定是抽象类(或者接口), 但是抽象类(接口)中不一定有抽象方法.
  3. 接口不能直接实例化.
    问: 那接口怎么实例化呢?
    答: 通过 接口多态 实现, 即: 创建该接口的子类对象即可.
  4. 接口的子类.
    如果是普通类: 则必须重写该接口中所有的抽象方法.
    如果是抽象类: 则可以不用重写父接口中的抽象方法.

接口的成员特点

JDK1.5及其以前: 接口中有且只能有 常量, 抽象方法.
因为你写的变量, 默认会有: public static final 修饰.
因为你写的方法, 默认会有: public abstract 修饰.
JDK1.8及其以后: 接口中可以写 静态方法 和 默认方法了.
静态方法: 要用static修饰.
默认方法: 要用default修饰, 其实就是我们写的非静态方法.

接口 和 (抽象)类的区别

  1. 成员特点区别.
    接口: 有且只能有常量, 抽象方法, JDK1.8开始, 可以有静态方法 和 默认方法.
    类: 变量, 常量, 构造方法, 抽象方法, 静态方法, 非静态方法.
  2. 关系特点区别.
    类与类: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
    类与接口: 实现关系, 既可以单实现, 也可以多实现, 还可以在继承1个类的同时, 实现多个接口.
    接口与接口: 继承关系, 可以单继承, 也可以多继承.
  3. 设计理念的区别.
    抽象类: 一般充当父类, 定义的是整个继承体系的 共性内容.
    接口: 一般充当父接口, 定义的是整个继承体系的 扩展内容.

Jumping(接口类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//接口, 表示具有跳高功能.
public interface Jumpping {
//接口中的变量, 默认有: public static final修饰.
public static final int a = 10;

//接口中的方法, 默认会加: public abstract
public abstract void jump();

//JDK1.8及其以后, 可以写: 静态方法.
public static void show() {
System.out.println("JDK1.8开始, 接口可以写静态方法");
}

//JDK1.8及其以后, 可以写: 非静态(默认)方法.
public default void method() {
System.out.println("JDK1.8开始, 接口可以写默认方法");
}

JumpCat(继承自接口)

1
2
3
4
5
6
7
//表示会跳高的猫, 继承自: Cat类(亲爹), 实现 Jumpping接口(干爹)
public class JumpCat extends Cat implements Jumpping, Inter1, Inter2{
@Override
public void jump() {
System.out.println("经过训练, 这批猫学会了 跳高!");
}
}

Animal类(父类)

1
2
3
4
5
6
//动物类
public class Animal {
public void eat() {
System.out.println("动物会吃!");
}
}

Cat类(继承自Animal类)

1
2
3
4
5
6
//猫类, 继承自: 动物类.
public class Cat extends Animal{
public void catchMouse(){
System.out.println("猫会抓老鼠!");
}
}

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Demo01 {
public static void main(String[] args) {
//普通方式, 创建JumpCat类的对象.
JumpCat jc = new JumpCat();
jc.jump(); // 从 父接口 继承过来的方法
jc.catchMouse(); // 从 父类 继承过来的方法
jc.eat(); // 从 父类的父类 继承过来的方法
System.out.println("--------------------------");

//普通类多态, 创建 跳高猫对象.
Animal an = new JumpCat();
an.eat(); //从 父类的父类 继承过来的方法
System.out.println("--------------------------");

Cat c = new JumpCat();
c.catchMouse(); // 从 父类 继承过来的方法
c.eat(); // 从 父类的父类 继承过来的方法
System.out.println("--------------------------");

//接口多态, 创建跳高猫对象.
Jumpping jm = new JumpCat();
jm.jump(); // 从 父接口 继承过来的方法
System.out.println("--------------------------");

//测试: 接口的成员特点.
//Jumpping.a = 100; 接口中的变量都是常量, 只能赋值一次, 不能修改.
System.out.println(Jumpping.a); // 10

Jumpping.show(); //接口名. 的方式调用 接口中的静态方法.

jm.method(); //接口(子类)对象名. 的方式调用 接口中的非静态方法(默认方法)
}
}

内部类

内部类介绍:

内部类的本质: 匿名内部类是1个 继承了该类, 或者实现了该接口的 匿名的 子类对象.

概述:

内部类指的是类里边还有1个类, 里边的类叫: 内部类, 外边的类叫: 外部类.

分类:

根据内部类的定义位置不同, 内部类可以分为:
成员内部类: 一般是底层源码的时候会用, 表示对该类的功能做 加强, 扩展延伸. 例如: ArrayList
局部内部类: 一般用于快速的初始化某个抽象类(接口), 即: 创建它的子类对象.

匿名内部类:

概述:
没有名字的 局部内部类.
格式:
new 类名或者接口名() {
//重写类或者接口的所有抽象方法
};

本质: 重点.

匿名内部类是1个 继承了该类, 或者实现了该接口的 匿名的 子类对象.

应用场景:

   1. 匿名内部类可以作为 方法的实参 进行传递.
   2. 当对成员方法仅调用一次的时候.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class Demo01 {
public static void main(String[] args) {
//A a = new A();

//需求1: 调用Animal#eat()
//方式1: 抽象类多态.
Animal an = new Cat(); //an: 继承了Animal类的, 子类Cat类的对象.
an.eat();

//方式2: 匿名对象. //匿名对象: new Cat();
new Cat().eat(); //子类名: Cat, 对象名: 不知道

//方式3: 匿名内部类写法. 子类名: 不知道, 对象名: 不知道
new Animal(){
//重写类或者接口的所有抽象方法
@Override
public void eat() {
System.out.println("匿名内部类方式, 动物会吃");
}
}.eat();
System.out.println("-------------------------");


//需求2: 调用printAnimal()方法.
//思路1: 抽象类多态.
Animal an2 = new Cat();
printAnimal(an2);

//思路2: 匿名对象.
printAnimal(new Cat());

//思路3: 匿名内部类
printAnimal(new Animal(){
//重写类或者接口的所有抽象方法
@Override
public void eat() {
System.out.println("匿名内部类方式, 动物会吃");
}
});
}

//定义方法printAnimal(Animal an), 调用其eat()方法.
public static void printAnimal(Animal an) {
an.eat();
}
}

API简介

API全称是Application Programming Interface(应用程序编程接口), 本意指的是JDK提供的各种功能的Java类和接口, 但是我们常说的”打开API”并不是指打开这些Java类和接口, 而是打开API帮助文档.

API 帮助文档就相当于说明书,是用来介绍JDK提供的各个类和接口的功能的, 从而帮助我们快速上手使用.

API帮助文档的使用步骤:
1. 找到你要用的类.
2. 看类的结构.
即: 父类是谁, 有哪些子类, 在哪个包下等…
如果 java.lang 包下的类, 可以直接使用, 其它包下的类, 用之前需要导包.
3. 大概的看下类的说明, 知道该类是干啥的.
4. 看构造方法.
有构造: 说明方法基本上都是 非静态的, 需要通过 对象名. 的方式调用.
无构造: 说明方法基本上都是 静态的, 可以通过 类名. 的方式调用.
5. 具体的调用方法的过程.
注意方法名大小写, 别写错了, 传参, 接收返回值等…

常用API

Scanner类的踩坑经验

问题描述

1
2
3
public int nextInt();       接收用户录入的 整数
public String next(); 接收用户录入的 字符串, 只接收空格前的内容.
public String nextLine(); 接收用户录入的 字符串, 接收所有.

遇到的问题:
先用nextInt()接收整数, 再用nextLine()接收字符串, 会导致 字符串无法录入的情况.
产生原因:

   1. nextInt() 和 nextLine()的结束标记都是: \r\n
   2. nextInt() 只接收用户录入的数字, 不接收最后的 回车换行符(\r\n)
   3. nextInt()"遗留"下来的 \r\n, 被nextLine()直接识别了, 导致nextLine()直接结束.

解决方案:
思路1: 用next()方法 替换 nextLine()
思路2: 重新调用1次nextLine()
思路3: 重新new 1个Scanner对象.
思路4: 实际开发解决方案, 都用字符串接收, 然后把字符串形式的数字 转成 int类型的数字.
包装类写法: int num = Integer.parseInt(“123”); “123” => 123

Demo(测试)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Demo01 {
public static void main(String[] args) {
//1. 创建Scanner对象.
Scanner sc = new Scanner(System.in);
//2. 接收用户录入的数字, 并打印.
System.out.println("请录入您的年龄: ");
//int age = sc.nextInt(); // 18 + 回车(\r\n)
String ageStr = sc.nextLine();
//把上述的字符串形式的数字, 转成整数(int), 超纲了, 先看, 下午讲课.
int age = Integer.parseInt(ageStr); // "18" => 18
System.out.println("年龄: " + age + ", 3年后, 您的年龄是: " + (age + 3));
//3. 接收用户录入的字符串, 并打印.
System.out.println("请录入您的姓名: ");
//思路1: 用next()方法 替换 nextLine()
//String name = sc.next();
//思路2: 重新调用1次nextLine()
//String name = sc.nextLine();
//name = sc.nextLine();
//思路3: 重新new 1个Scanner对象.
//sc = new Scanner(System.in);
String name = sc.nextLine();
System.out.println("姓名: " + name);
}
}

Object类

概述:
它是java.lang包下的类, 可以直接使用, 无需导包.
它是所有类的父类, 任何的类都直接或者间接继承自Object, Object类是所有类的父类, 基类, 超类.
构造方法:
public Object() 它里边只有1个默认的 公共的 空参构造, 回顾: 我之前说过, 类你不写构造方法, 系统默认给1个 公共的无参构造.
成员方法:
public String toString(); 默认打印的是对象的地址值, 无意义, 一般会重写它, 改为打印该对象的各个属性值.
public boolean equals(Object obj); 默认比较的是地址值, 无意义, 子类一般都会重写该方法, 改为比较: 对象的各个属性值.
细节:

1. 输出语句直接打印对象, 默认调用了该对象的 toString()方法.
2. 实际开发中, 我们认为, 同一个类的对象, 只要各个属性值相同, 它们就是同1个对象, 例如:
    Student s1 = new Student("张三", 23);
    Student s2 = new Student("李四", 24);
   因为s1 和 s2都是学生对象, 且各个属性值都相同, 实际开发中, 我们会认为: s1 和 s2是同1个对象.

记忆:
以后写JavaBean类的时候, 记得重写下 Object#toString(), equals() 功能.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Demo02_Object {
public static void main(String[] args) {
//案例1: 演示Object类的toString()方法.
Student s1 = new Student("乔峰", 29);
System.out.println(s1); // com.itheima.demo05_api.Student@b4c966a
System.out.println(s1.toString()); // com.itheima.demo05_api.Student@b4c966a
System.out.println("---------------------");
//案例2: 测试Object#equals()方法
Student s2 = new Student("乔峰", 30);
//实际开发中, 因为s1和s2的各个属性值都相同, 所以它们是同1个对象.
System.out.println(s1.equals(s2)); //false, 默认比较地址值, 如果重写了, 打印结果是true.
}
}

String类

概述:

它表示字符串类, 每1个字符串值, 例如: “a”, “abc”都是它(String)的示例.

常用成员方法:

1
2
3
4
public boolean equals(Object obj)           比较两个字符串的内容是否相同, 区分大小写.
public boolean equalsIgnoreCase(String s) 比较两个字符串的内容是否相同, 不区分大小写.
public int length() 获取字符串的长度
public char charAt(int index) 根据索引, 获取该索引对应的字符.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Demo03_String {
public static void main(String[] args) {
//测试: public boolean equals(Object obj) 比较两个字符串的内容是否相同, 区分大小写.
System.out.println("abc".equals("abc")); //true
System.out.println("abc".equals("ABC")); //false
System.out.println("------------------------------");
//测试: public boolean equalsIgnoreCase(String s) 比较两个字符串的内容是否相同, 不区分大小写.
System.out.println("abc".equalsIgnoreCase("abc")); //true
System.out.println("abc".equalsIgnoreCase("ABC")); //true
System.out.println("------------------------------");
//测试: public int length() 获取字符串的长度
//String s1 = new String("abcde"); // 可以这样写, 但是不用, 因为String类型很常用, 所以针对于它, 有语
String s1 = "abcde";
System.out.println(s1.length());
System.out.println("------------------------------");
//测试: public char charAt(int index) 根据索引, 获取该索引对应的字符.
System.out.println(s1.charAt(1)); // b
}
}

StringBuilder

概述:

它叫字符串缓冲区类, 主要涉及到 大量字符串拼接操作等的, 不会开辟新空间, 而是在 该对象空间中, 直接拼接.
它是java.lang包下的类, 可以直接使用, 无需导包.

构造方法:

1
2
public StringBuilder()              空参构造, 创建StringBuilder对象.
public StringBuilder(String s) 带参构造, 根据传入的字符串值, 转成其对应的StringBuilder对象形式.

成员方法:

1
2
3
public StringBuilder append(任意类型);      往字符串缓冲区对象中 添加元素, 返回自身.
public StringBuilder reverse(); 反转元素内容, 返回自身.
public String toString(); 把StringBuilder对象 => String对象.

细节:

String 和 StringBuilder之间的区别?
String: 内容固定.
StringBuilder: 内容可变.
blic class Demo04_StringBuilder {

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Demo04_StringBuilder {
public static void main(String[] args) {
//问: 分析如下的代码, 执行效率高, 还是低?
//答: 低, 因为字符串值是常量, 在内存中(方法区的常量池)只存储1份, 常量值是不能修改的, 每次操作都会创建新的 字符串值(对象).
String s = "hello";
s += "world";
System.out.println(s);
System.out.println("-------------------------");

//案例1: StringBuilder入门.
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder("abc");
StringBuilder sb3 = sb2.append("xyz");
StringBuilder sb4 = sb2.append("true");

//打印地址值(内容), 因为StringBuilder类已经重写Object类的toString().
System.out.println(sb2); // abcxyztrue
System.out.println(sb3); // abcxyztrue
System.out.println(sb4); // abcxyztrue

System.out.println(sb2 == sb3); //true
System.out.println(sb3 == sb4); //true
System.out.println("-------------------------");

//反转元素.
sb2.reverse();
System.out.println(sb2); // eurtzyxcba
System.out.println(sb3); // eurtzyxcba
System.out.println(sb4); // eurtzyxcba
System.out.println("-------------------------");

//把 StringBuilder 转成 String类型.
String str = sb2.toString();
System.out.println(str);

}
}

Arrays工具类

概述:
它属于java.util包下的类, 用之前需要导包.
它表示数组工具类, 里边定义的大多数都是操作数据的方法, 例如: 排序, 查找, 打印等…
成员方法:
public static void sort(int[] arr); 对数组元素排序, 默认: 升序.
public static String toString(int[] arr); 把数组元素拼接成字符串, 格式为: “[值1, 值2, 值3…]”
细节:
1. 问: 什么是工具类呢?
答:
特点1: 构造方法私有化. 目的: 不让外界创建该类的对象.
特点2: 成员都是静态的. 可以通过 类名. 的方式调用.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
public class Demo05_Arrays {
public static void main(String[] args) {
//1. 定义数组.
int[] arr = {1, 3, 2, 5, 7};
//2. 对数组元素排序.
Arrays.sort(arr);
//3. 打印数组元素.
//3.1 通过Arrays#toString(), 把 int[] => String
String result = Arrays.toString(arr);
System.out.println("结果为: " + result);
}
}

包装类

包装类的由来:

我们知道Java的数据类型分为 基本类型 和 引用类型, 引用类型是可以创建对象的, 通过对象名. 或者 类名. 的方式就可以调用该类的很多方法.

但是基本类型是不能直接创建的对象, 例如: int a = 10; 这个是无法直接new的, 就有点不符合Java的 面向”对象”的思维, 于是就有了 包装类,
所谓的包装类, 其实就是: 基本类型 对应的 引用类型. 这样就完美了, Java中所有的类型都可以有 对象形式了.

基本类型 和 对应的包装类型之间的关系:

1
2
3
4
5
6
7
8
9
基本类型        对应的包装类型(引用类型)
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double
boolean Boolean

问: 为啥要用包装类呢?

就是为了学习包装类中的 parseXxx()方法, 用来把 字符串值 转成对应的 基本类型.
例如:

1
2
3
Integer#parseInt(),   可以把字符串数字(例如: "123") 转成 int类型的 123
Double#parseDouble(), 可以把字符串数字(例如: "10.3") 转成 double类型的 10.3
Boolean#parseBoolean(), 可以把字符串布尔值(例如: "true") 转成 boolean类型的 true

细节:

1
2
3
4
5
6
7
1. parseXxx()方法, 除了Character类之外, 都有.  因为Character表示字符, 它和字符串之间有特殊的转换方式.
例如:
"abc" => 'b' "abc".charAt(1)
'b' + "" => "b"
2. 自动拆装箱解释, 它是JDK1.5的新特性.
自动装箱: 把基本类型 转成对应的 包装类型. Integer i1 = 10;
自动拆箱: 把包装类 转成对应的 基本类型. int a = i1;

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Demo06_包装类 {
public static void main(String[] args) {
//案例1: 把 int => String
int a = 10;
String s = "" + a;
System.out.println(s);
System.out.println("-----------------------");

//案例2: 把 String => Int
//方式1: String => Integer => Int, 已过时(能用, 但是不推荐)
String s1 = "123";
Integer i1 = new Integer(s1); //String => Integer
int a1 = i1.intValue(); //Integer => int
System.out.println(a1 + 3); //验证是否转换成功.
System.out.println("-----------------------");

//方式2: 实际开发做法, Integer.parseInt("123");
int b = Integer.parseInt("123");
System.out.println(b + 2); // 125

double d = Double.parseDouble("10.3");
System.out.println(d + 2); // 12.3
System.out.println("-----------------------");

//案例3: 演示自动拆装箱.
//自动装箱: 把基本类型 转成对应的 包装类型. Integer i1 = 10;
Integer i2 = new Integer(10); // 装箱.
Integer i3 = 100; // 自动装箱.

//自动拆箱: 把包装类 转成对应的 基本类型. int a = i1;
int aa = i2.intValue(); // 拆箱.
int bb = i2; // 自动拆箱.
}
}

Date类

概述:
它表示时间(日期), 可以精确到 毫秒.
它属于java.util包下的类, 用之前需要先导包.
构造方法:
public Date(); 默认用系统当前的时间.
public Date(long seeds); 根据传入的时间种子, 获取指定时间, 如果种子一致, 则获取的时间也是一样的.
成员方法:
public void setTime(long Time); 设置时间的.
public long getTime(); 获取时间的(单位: 毫秒)
目的:
讲Date类的目的不是真正让你学会它, 而是让你懂怎么操作日期, 如果你去API中查看对Date类的解释, 你会发现,
该类(java.util.Date类)中 大多数的方法都已经过时了. 已经被 Calendar类(日历类) 替代了.
遇到的两个问题:
1. Date类的格式看起来不舒服(例如: Thu Jan 01 08:00:02 CST 1970), 如何改成: 1970/01/01 08:00:02 形式?
通过 SimpleDateFormat类实现.
2. 观察API帮助帮助文档, 发现Date类绝大多数方法已经被Calendar替代了, Calendar类怎么用?

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Demo07_Date类 {
public static void main(String[] args) {
//1. 创建Date对象, 空参.
Date d = new Date();
System.out.println(d); // 不是地址值, 说明Date类重写了Object#toString(), Fri Sep 01 17:13:12 CST 2023

//2. 创建Date对象, 带参.
Date d2 = new Date(2000L); // 2000L表示毫秒, L是long类型值的写法, 后续要加字母L
System.out.println(d2); // Thu Jan 01 08:00:02 CST 1970
System.out.println("----------------------------");

//3.演示getTime()方法.
Date d3 = new Date();
System.out.println(d3.getTime()); // 获取从时间原点(1970年1月1日 08:00:00) 至今, 过了多少毫秒. 1693559837897

d3.setTime(1000L); //设置时间为: 时间原点往后推移 1s, 1970年1月1日 08:00:01
System.out.println(d3);
}
}

SimpleDateFormat类

概述:
它叫日期格式化类, 主要是用来在 字符串 和 日期对象之间做转换的.

构造方法:

1
2
public SimpleDateFormat();                  创建SimpleDateFormat对象, 采用默认模块.
public SimpleDateFormat(String pattern); 创建SimpleDateFormat对象, 采用指定模块.

成员方法:

1
2
public String format(Date d);               把 Date 日期对象 => String字符串.
public Date parse(String dateStr); 把 String字符串日期 => Date日期对象.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Demo08_SimpleDateFormat {
public static void main(String[] args) throws ParseException {
//案例1: 演示 日期的格式化操作, 即: Date 日期对象 => String字符串.
//1. 创建日期对象.
Date d1 = new Date();
System.out.println(d1);
//2. 创建SimpleDateFormat 日期格式化对象.
//SimpleDateFormat sdf = new SimpleDateFormat(); //默认模板格式: 2023/9/1 下午5:44
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //指定模板格式.
//具体的 格式化 动作
String s = sdf.format(d1);
System.out.println("格式化后, 结果为: " + s);
System.out.println("-----------------------");

//案例2: 演示 日期的解析操作, 即: 把 String字符串日期 => Date日期对象.
String str = "2023/09/01 13:14:21";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); //解析的时候, 模板必须和 字符串日期保持一致.
//具体的 解析 动作
Date d2 = sdf2.parse(str); //有异常, ParseException, 转换异常.
System.out.println("解析后, 结果为: " + d2);
}
}

Calendar类

概述:

它表示日历类, 里边绝大多数的方法, 都是用来替代Date类的.
它是java.util包下的类, 用之前需要先导包.
它(Calendar)是1个抽象类, 不能直接实例化, 可以通过创建它的子类对象来完成实例化, 抽象类多态.

成员常量:

1
2
3
4
5
public static final int YEAR;               年
public static final int MONTH; 月, 范围: 0 ~ 11
public static final int DATE; 日
public static final int DAY_OF_MONTH; 月中的第几天, 同上
public static final int DAY_OF_YEAR; 年中的第几天.

成员方法:

1
2
3
4
public static Calendar getInstance();           底层会通过抽象类多态的方式, 创建 Calendar类的对象.
public int get(int field); 根据传入的日期字段, 获取其对应的 值.
public void set(int year, int month, int day); 设置时间为, 年, 月, 日.
public void add(int field, int amount) 把指定的日期偏移指定的值, 例如: 往前推几天, 往后推几月.

Demo(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Demo09_Calendar {
public static void main(String[] args) {
//1. 创建Calendar类的对象.
Calendar c = Calendar.getInstance();

//2. 演示Calendar的日期字段.
System.out.println(c.get(1)); // 2023 年, 看看就行了, 不推荐.
System.out.println(c.get(Calendar.YEAR)); // 2023 年
System.out.println(c.get(Calendar.MONTH)); // 8, 范围: 0 ~ 11
System.out.println(c.get(Calendar.DATE)); // 1
System.out.println(c.get(Calendar.DAY_OF_MONTH)); // 1
System.out.println(c.get(Calendar.DAY_OF_YEAR)); // 244
System.out.println("----------------------------");

//3. 演示Calendar的成员方法
c.set(2000, 5, 10); //设置时间为: 2000年6月10日

// 4. 让时间偏移指定的值.
c.add(Calendar.YEAR, 8); //往后加8年, 2008年6月10日

System.out.println(c);

}
}