JavaSE进阶——Day03 多态、内部类、时间日期格式类

JavaSE进阶——Day03 该篇主要讲解Java中的多态内部类、时间日期格式类

学习目标

  • 多态

    • 多态的前提

    • 多态的成员访问特点

    • 多态的优缺点

    • 多态的转型

  • 内部类

    • 成员内部类

    • 匿名内部类

  • 常用API

    • Object类

    • Objects类

    • Date类

    • SimpleDateFormat类

    • LocalDateTime类

    • Period & Duration

    • Math类 & System类

回顾

工具类的书写规则:

  1. 工具类,修饰为final(不让继承)
  2. 工具类的构造方法,设置为private(不让其他类创建对象)
  3. 工具类中提供:静态方法(通过类名访问)

static关键字

  • 解决程序中什么问题?

    1
    2
    静态变量:共享数据
    静态方法:工具类中方法的编写
  • 怎么使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class 类{
    static 类型 变量名;

    public static 返回值类型 方法名(参数, ..){

    }
    }

    类名.静态变量名=100;
    类名.静态方法名();
  • 细节:

    1. 静态内容是随着类的加载,存放在方法区的静态区域下(仅有一份)【早于对象创建】
    2. 静态方法中不能使用this关键字
    3. 静态方法只能访问静态内容(静态变量、静态方法)

final关键字

  • final修饰的类, 不能继承
  • final修饰的方法, 不能被重写
  • final修饰的变量, 初始化值后不能修改其值(变为常量)

代码块:

1
2
3
static{
//在对象创建之前,初始化数据
}

接口:

  • 接口的作用:制定规则

  • 接口的使用

    • 接口定义(制定规则)

      1
      2
      3
      4
      5
      6
      public interfce 接口名{
      //常量
      public static final String 常量名 = 值;
      //抽象方法(制定规则)
      public abstract 返回值类型 方法名(参数, ...);
      }
    • 接口实现(按照规则实现代码)

      1
      2
      3
      public 接口实现类 implements 接口名{
      //重写接口中的抽象方法
      }

问题:在继承时,子类可能把父类的构造方法继承了吗?

答案:不可以。

枚举:

  • 解决什么问题?

    1
    当程序中的某个数据有固定在一定范围的取值时,为保障程序中数据的有效性,可以使用:枚举
  • 使用方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public enum 枚举名{
    固定选项值1,固定选项值2,...;
    }

    枚举名.选项值;




    public enum Sex{
    BOY,GIRL;
    }

    public class Student{


    private Sex sex;

    }


    Student stu = new Student( Sex.BOY )

多态

什么是多态?

1
2
3
4
5
6
7
8
9
10
11
12
多态:多种形态

多种形态:
同一个对象,在不同时刻表现出来的不同形态
Cat extends Animal
第一种形态: Cat c1 = new Cat(); //c1是只猫
第二种形态: Animal c2 = new Cat(); //c2是个动物

举例:
数字2
10进制:2
2进制: 00000010

多态解决程序中的什么问题?

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
47
1、提高代码的复用性
2、提高代码的扩展性


public interface Player{
public void play();
public void stop();
}

public MP3 implements Player{
public void play(){
System.out.println("mp3播放")
}
public void stop(){
System.out.println("mp3停止")
}
}
public MP4 implements Player{
public void play(){
System.out.println("mp4播放")
}
public void stop(){
System.out.println("mp4停止")
}
}


public static void main(String[] args){
MP3 mp3 = new MP3();
method( mp3 )

MP4 mp4 = new MP4();
method( mp4 )
}

//多态的体现: Player p = new MP3 / MP4 ();

public static void method( Player p )// Player p = new MP4()
{
p.play();
p.stop();
}



//集合: ArrayList类 implements List接口 、 LinkedList类 implements List接口
List list = new LinkedList();

多态的使用

1
2
3
//多态的代码体现格式:  
父类型 对象 = new 子类(); //大类型包含小类型 int a=10; long b = a;

多态在使用时的注意细节

  1. 多态中:父类和子类拥有一模一样的成员变量时:
    • 编译时:以父类型中的成员变量为主
    • 运行时:使用父类中的成员变量
  2. 多态中:父类和子类拥有一模一样的成员方法时:
    • 编译时:以父类中的成员方法为主(检查父类中有没有这个成员方法,没有:报错)
    • 运行时:以子类中的成员方法为主(调用子类对象中重写后的成员方法)

多态转型

  • 向上转型(自动类型提升)

    1
    2
    3
    4
    //基础班: int a =10;   long  num = a;  

    //多态:
    父类型 父引用 = new 子类(); //子类型变为:父类型 (弊端:父引用不能使用子类特有成员)
  • 向下转型(强制类型转换)

    1
    2
    3
    4
    5
    6
    //解决的问题: 父引用不能使用子类中特有成员

    //基础班: long a =100L; int b = (int) a;

    //多态的向下转型:
    子类 对象 = (子类) 父引用;
    • 注意细节:

      • 向下转型时容易发生:java.lang.ClassCastException(类型转换异常)

        解决方案:instanceof

        1
        2
        3
        4
        if( 父引用对象  instanceof 子类型 ){
        子类型 对象 = (子类型)父引用对象;
        对象.特有成员
        }

多态代码的书写:

  1. 创建对象

    1
    2
    //父类型  父引用 = new 子类()
    Father f = new Son();
  2. 作为参数

    1
    2
    3
    4
    public void method( Father f )
    {
    f.方法()
    }
  3. 作为返回值

    1
    2
    3
    4
    5
    public Animal getInstance()
    {
    //返回:子类对象
    return new Cat();
    }

内部类:

1
2
3
4
5
6
7
8
9
10
public class HelloWorld{
//成员变量

//成员方法

//在一个类中,定义了另外一个类(内部类[成员内部类])
class Hello{
}

}

问题:如何访问某个类中的成员变量or成员方法?

答案:创建类的对象,通过”对象名.成员”的方式访问

匿名内部类:

  • 解决程序中什么问题?

    1
    简化程序中代码的书写
  • 怎么使用?

    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
    //语法格式:
    new 类名/接口(){
    //重写方法
    }

    //示例:
    public class Father{
    public String sayHello(String name){
    return "早上好, "+ name;
    }
    }
    //此时:程序的需求发生改变,要求sayHello方法的返回值为"你好,名字"

    public class Son extends Father{
    //重写sayHello方法
    public String sayHello(String name){
    return "你好, "+name;
    }
    }


    //以下代码使用匿名内部的方式(其实本质就是一个子类对象)
    new Father(){
    //把父类中的方法重写
    public String sayHello(String name){
    return "晚上好,"+name;
    }
    }

工具类:为解决某些特定问题,特意编写的公共类(程序员都可以使用)

  • JDK(java开发工具包) = JRE + 核心类库
    • 核心类库: jdk提供一些现成的功能,这些功能封装在不同的类中
  • JDK就提供了一些工具类:Math、Arrays
    • Arrays工具类:针对数组,提供了一系列现成的功能(例:排序)

总结

  • 多态

    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
    //多态可以解决程序中什么问题?
    1、提高程序中代码的复用性
    2、提高程序中代码的扩展性

    //多态怎么使用?
    //1、创建一个对象
    父类型 父引入 = new 子类();
    //2、作为参数
    public void method(父类型 父引用){
    父引用.成员方法()
    }
    //3、作为返回值
    public 父类型 getInstance(){
    return 子类对象;
    }

    //多态在使用中的细节
    父子类中有相同的成员变量时:编译和运行都以父类型中的成员变量为主
    父子类中有相同的成员方法时:编译时检查父类型中的成员方法是否存在
    运行时以子类对象中的重写的方法为主

    //多态的转型
    向上转型: 父类型 父引入 = new 子类(); //弊端:父引用不能访问子类对象中特有成员
    向下转型: 子类 对象 = (子类) 父引用; //向下转换后,可以访问子类对象中特有成员
    在向下转型时容易发生:ClassCastException 异常
    使用:instanceof 避免 ClassCastException异常发生
    if(父引用 instanceof 子类类型){
    子类 对象 =(子类) 父引用;
    }
  • 匿名内部类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //匿名内部类解决什么问题?
    简化程序中的代码

    //匿名内部类的使用
    父类型 父引用 = new 父类/接口(){
    //重写父类型中的方法
    };

    //作为参数
    public void show( Flyable fly );

    show( new Flyalbe(){
    //重写方法
    } );



    //作为返回值
    public Flyable getInstance(){
    return new Flyable(){
    //重写方法
    };
    }

在Java继承体系中,有一个顶层父类:Object(鼻祖类)

  • 在java语言中,程序员自定义的类或者jdk中存在的类,直接或间接都要继承Object
  • 继承了Object类后,就可以使用Object提供的相关方法:
    • boolean equals(Object obj)
      • boolean: 方法的返回值类型
      • Object: 方法传递参数的类型
      • 作用:比较两个对象是否相同(比较两个对象的地址值是否相同)
    • String toString()
      • 作用: 把对象转换为字符串

比较两个字符串是否相同 :

1
2
3
4
5
6
7
8
//方案1: String类中的equals方法
boolean result = 字符串1.equals(字符串2);

//方案2:Objects工具类中的equals方法
boolean result = Objects.equals(字符串1 , 字符串2);


区别:Objects工具类中的equals方法 可以避免NullPointerException异常的发生

日期类型的数据:

1
2
3
4
5
6
7
8
9
10
public class Emp
{
//姓名
private String name;//String表示字符串
//年龄
private int age;//int表示整数
//生日
private Date birthday;//Date表示日期

}

Date类:

  • 归属包:java.util

  • 作用:表示日期时间(精确到毫秒)

  • 使用:

    • 构造方法(创建对象)

      1
      2
      public Date()
      public Date(long time)
    • 常用方法

DateFormat类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//DateFormat类是什么
DateFormat类是java语言提供的日期格式化类

//DateFormat类解决什么问题
对日期进行格式化操作:Date类型 -> String类型 => String format(Date)
对日期进行解析操作:String类型 -> Date类型 => Date parse(String )

//DateFormat类怎么使用
java.text.DateFormat
DataeFormat是一个抽象类,无法实例化。使用子类:SimpleDateFormat
DateFormat df = new SimpleDateFormat("日期模板");
//日期模板:就是使用一些特定的字符,来表示某个日期。例:yyyy表示全年 MM表示月 dd表示日

DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

String format(Date date) //将Date类型的数据,按照日期模板,转换为字符串
Date parse(String s) //将日期格式的字符串数据,按照日期模板,转换为Date对象

Calendar类:日历类(存储的有日期、时间、日历信息)

  • 代替java.util.Date类中的过期方法
1
2
3
4
5
6
7
8
9
//Calendar类的使用: 构造方法、 常用方法
//Calendar类是一个抽象类,无法创建对象。 子类:GregorianCalendar

//在Calendar类中,提供了一个静态方法,该静态方法可以实现:Calendar对象的实例化(底层还是使用GregorianCalendar子类)

//获取Calendar类对象
Calendar c = Calendar.getInstance();


Calendar对象中存储的内容:

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
java.util.GregorianCalendar[
time=1667208388632,
areFieldsSet=true,
areAllFieldsSet=true,
lenient=true,

zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",

offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],

firstDayOfWeek=1,

minimalDaysInFirstWeek=1,ERA=1,

YEAR=2022,
MONTH=9, //月份:0~11
WEEK_OF_YEAR=45,

WEEK_OF_MONTH=6,

DAY_OF_MONTH=31,

DAY_OF_YEAR=304,
DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=5,AM_PM=1,

HOUR=5,
HOUR_OF_DAY=17,

MINUTE=26,

SECOND=28,

MILLISECOND=632,

ZONE_OFFSET=28800000,DST_OFFSET=0]

获取Calendar对象中存储的数据:

1
2
3
4
5
6
7
//API方法:  public  int  get(int 字段名)  //字段名:YEAR     MONTH    DAY_OF_MONTH
在Calendar类中有一些静态常量: YEAR MONTH DAY_OF_MONTH
Calenar.YEAR Calendar.MONTH

//获取日历对象中的年
Calendar c = Calendar.getInstance();
int year = c.get( Calenar.YEAR )

给日历对象设置具体的:年月日时分秒……

1
2
3
4
5
6
7
8
//获取日历对象中的年
Calendar c = Calendar.getInstance(); //日历对象是基于当前系统日期时间获取的

//修改日历对象中的信息 public void set(int 字段 , int 数值)
c.set( Calendar.YEAR , 2000 );

//修改日历对象中的年月日
c.set( 2000, 9, 31 );

给日历对象中的信息,增加或减少

1
public void add(int 字段  , int 数值) //数值是负数是减少 , 数据是正数表示增加