1、日期时间转换
1.1、DateFormat类
在学习Date类的时候,Date类中大部分的方法都过时,同时提示可以使用相关的类代替。



其中提到解析和格式化到底什么意思呢?其实就是在说明DateFormat类是用来完成String和Date之间的转换的。
格式化:是将Date对象转成一定形式的字符串数据。
解析:是字符串形式的日期数据转成Date对象。
因此可以知道其实DateFormat类的主要功能就是完成Date对象和字符串形式的日期时间的转换的(本身使用Date类完成,但是Date类中的方法都过时了)。
1.2、演示DateFormat类
/*
* 演示DateFormat的使用
*/
public class DateFormatDemo {
public static void main(String[] args) {
/*
* 按照前面学习的方式,得到一个类的对象现在有两种方式:
* 1、通过new关键字创建。
* 2、类似于单例的那种方式,在类中提供静态方法获取
* DateFormat类,不能直接通过new关键字创建,只能通过其中的静态方法获取
*/
DateFormat df = DateFormat.getDateInstance();
// 创建Date对象
Date d = new Date();
// 将Date对象转成(格式化)字符串形式的时间数据
String time = df.format(d);
System.out.println(time);
/*
* 上面代码输出的数据是:2017-10-15
* 如果需要将Date对象转成由自己指定的格式,例如xxxx年xx月xx日,
* DateFormat类无法转成
*/
}
}
1.3、演示SimpleDateFormat类
由于DateFormat类对日期和字符串进行转换的时候格式不能由自己指定。因此Java提供了SimpleDateFormat类,它的功能更加强大,可以完成更加复杂的转换。

/*
* 演示SimpleDateFormat类使用
*/
public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
demo();
demo2();
demo3();
}
/*
* 演示将Date对象转成字符串格式。使用默认样式
*/
public static void demo() {
/*
* SimpleDateFormat类给我们提供多个构造方法可以用于创建对象
*/
// 使用空参数的SimpleDateFormat构造方法创建出的对象采用的格式就是默认的方式
SimpleDateFormat sdf = new SimpleDateFormat();
// 创建Date对象
Date d = new Date();
// 格式化
String time = sdf.format(d);
System.out.println(time);
}
/*
* 演示按照指定格式进行Date和字符串的转换
*/
public static void demo2() {
/*
* 使用SimpleDateFormat(String pattern) 构造方法创建出的对象采用
* 格式指定的格式完成Date和字符串时间数据转换。
* 具体的格式书写要求:
* 年:yyyy
* 月:MM
* 日:dd
* 时:hh
* 分:mm
* 秒:ss
* 年月日时分秒之间的分隔符由自己指定,例如:
* yyyy年MM-dd日 hh时mm分ss秒
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM-dd日 hh时mm分ss秒");
Date d = new Date();
// 格式化
String time = sdf.format(d);
System.out.println(time);
}
/*
* 演示将字符串格式的时间数据转成Date对象
*/
public static void demo3() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM-dd日 hh时mm分ss秒");
String time = "2017年10-15日 04时46分10秒";
// 解析
Date d = sdf.parse(time);
System.out.println(d);
}
}

1.4、面试题
/*
* 计算两个字符串格式的日期时间相隔多少天?
* "2017-07月12 13:14:55"
* "2017年09-01 17:58:05"
*
* 将字符串形式的时间转成Date对象,再调用Date类中的getTime方法,获取它们各自的毫秒值
* 然后计算时间差,最后得到天数。
*/
public class DateDemo {
public static void main(String[] args) throws ParseException {
//字符串形式的时间
String s1 = "2017-07月12 13:14:55";
String s2 = "2017年07-13 13:14:54";
// 定义SimpleDateFormat类完成字符串转成Date对象
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM月dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM-dd HH:mm:ss");
// 将字符串转成Date对象
Date d1 = sdf1.parse(s1); // 异常
Date d2 = sdf2.parse(s2); // 异常
// 通过Date对象获取到各自对应的毫秒值
long t1 = d1.getTime();
long t2 = d2.getTime();
long day = (t2 - t1) / 1000 / 60 / 60 / 24;
System.out.println(day);
}
}
2、Calendar类
2.1、介绍Calendar类

Calendar类中封装的是当前系统的时间对应的年月日时分秒的具体数据信息。可以通过get方法获取,或者通过set方法修改。以及通过add方法在原有的年月日时分秒上进行+和-操作。
SimpleDateFormat完成日期时间和字符串格式的日期时间的相互转后。而Calendar类仅仅是对时间进行修改的。
2.2、演示Calendar类
/*
* 演示Calendar类
*/
public class CalendarDemo {
public static void main(String[] args) {
// 调用getInstance方法,获取Calendar对象
Calendar c = Calendar.getInstance();
// 获取年
int year = c.get(Calendar.YEAR);
// 获取月 从0开始
int month = c.get(Calendar.MONTH);
// 获取日
int day = c.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "-" + month + "-" + day);
/*
* set方法设置当前年月日时分秒 set( Calendar.MONTH, 13 )
* 将Calendar中的月份设置成13,其实应该是14月。 时间就会自动转换到下一年的某个月份
*/
c.set(Calendar.MONTH, 13);
// 获取年
year = c.get(Calendar.YEAR);
// 获取月 从0开始
month = c.get(Calendar.MONTH);
// 获取日
day = c.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "-" + month + "-" + day);
/*
* add 方法 :
* 第一个参数:年月日时分秒
* 第二个参数:给当前的某个时间添加或减少具体的数据
* 正数:加
* 负数:减
*/
c.add(Calendar.MONTH, -13);
// 获取年
year = c.get(Calendar.YEAR);
// 获取月 从0开始
month = c.get(Calendar.MONTH);
// 获取日
day = c.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "-" + month + "-" + day);
}
}
2.3、Calendar练习
/*
* 任意一年2月有多少天?
*/
public class CalendarDemo2 {
public static void main(String[] args) {
/*
* 能够被4整除,不能被100整除,或者能被400整除
*/
int year = 1234;
if( (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ){
System.out.println(year + "是闰年");
}
/*
* Calendar类表示的就是年月日时分秒的信息,可以获取Calendar对象之后
* 调用set方法,将年月日设置成某年的3月1日,然后使用add方法让月中的天数-1.
* 时间就会变回某年的2月最后一天。然后get方法得到月中的天数
*/
Calendar c = Calendar.getInstance();
for( int y = 1500 ; y < 3000 ; y++ ){
// 使用set方法改年月日
c.set(y, 2, 1);
// 使用add 方法让月中的天数-1
c.add( Calendar.DAY_OF_MONTH, -1);
// 再获取月中的天数
int day = c.get( Calendar.DAY_OF_MONTH);
System.out.println(y +"年的2月有 :"+day +" 天!");
}
}
}
3、Java的继承技术
3.1、继承的引入
在学习日期时间格式化的时候,细节看SimpleDateFormat类的定义格式,会发现:

SimpleDateFormat extends DateFormat,这是什么意思呢?这个extends,就是Java中的另外一个非常重要的技术:“继承” 。
3.2、继承的代码体现
如果需要类和类之间有一定的继承关系存在,必须使用java中的extends关键字完成。
/*
* 演示Java中的继承技术
* 继承:
* 1、生活中的体现:子承父业、富二代、官二代、星二代。
* 2、Java中的继承:
* 在Java中使用类描述生活中的物体(群体、事物)。在实际描述的过程中
* 事物和事物之间或多或少会存在一定的关系。可以根据分析,得到某些类是否包含其他的类
* 如果存在这种关系,就需要使用Java中的继承来表示这种关系
*
* 类和类之间存在了继承关系之后:需要使用extends关键字来表示
* 子类:继承的类(Dog、Cat)
* 父类:被继承的类(Animal)
* 当多个子类中都有的共性的内容(成员变量和方法)都可以抽取之后,写在父类中,只要在父类中的任何成员(变量和方法),
* 子类是可以直接使用的。
*/
// 描述动物
class Animal{
//毛色
private String color;
//狗的年龄
private int age;
}
// 描述的狗
class Dog extends Animal{
public void lookHome(){
System.out.println("狗看门的行为");
}
}
// 描述猫
class Cat extends Animal{
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
3.3、继承的细节
注意:在生活中继承是有一定的规律(规则)。而在Java中,只要某个类通过extends关键字,就可以去继承其他类。进而就可以去使用这些类中的非私有的内容。如果仅仅站在Java代码的角度去理解继承,任何类之间几乎都可以进行继承。但是我们书写的类是在描述生活中的事物,因此这个继承也必须按照一定的规则进行。
继承好处:
一个类继承了另外一个类,就可以直接使用哪个被继承类中的内容。继承为后续的多态技术提供的方便。
继承的弊端:
打破了封装性,导致被继承类中的内容可能会暴漏给继承的类。
在继承中一些名词:
父类:被继承的类。例如上面代码中的Animal父类
子类:继承的类。例如上面代码中的Cat、Dog、Pig等他们就属性子类。
子类就可以使用父类中的内容。并且子类继承了父类,就相当于子类和父类同属于一个大的体系结构。
3.4、单继承&多继承
单继承:一个类只有一个父类。
多继承:一个类有多个父类。
在Java中不支持多继承。只支持单继承(一个子类永远只有一个父类)。但支持多重继承。
不支持多继承的原因:如果一个类有多个父类,那么就会导致子类使用父类的函数的时候出现一些不确定的因素。
class A{
public void demo(){}
}
class B{
public void demo(){}
}
class C extends A , B{
调用demo();这时就无法保证调用的到底是A父类中的demo,还是B父类中的demo。
}
Java语言在设计的时候,将这种有歧义的使用规则屏蔽了。
一个父类可以有多个子类。多个子类都可以去使用父类中的功能。
3.5、继承中函数同名(函数复写)
在学习函数(方法)的时候,我们学习了函数有重载的特性。
重载体现:在同一个类中,出现了同名的函数,但是参数列表不同(顺序、个数 overload)。
在继承中,如果子父类中出现了完全一样(返回值类型、函数名、参数列表)的函数,这时称为函数的复写(重写、覆盖 override)。
注意:如果出现函数复写,仅仅只有修饰符可以进行调整。
如果父类某个函数的修饰为private ,那么子类中出现的函数,可以是private,也可以是public。
如果父类的函数是public修饰的,子类要重写父类这个函数,那么修饰符也只能是public类型。
什么时候使用函数复写:
在继承中,如果子类与父类有相同的行为(功能),但是子类发现父类的行为不能满足自己的要求时,这时子类可以延用父类还是的定义方式,在自己的类中将函数体进行重写。
/*
* 继承:方法同名的问题(父类中的方法和子类中的方法同名)
*/
/*
* 描述宝马系列的车
*/
class BMW1{
public void run(){
System.out.println("普通的run方法,没有涡轮增压");
}
}
class BMW2 extends BMW1{
public void run2(){
System.out.println("BMW2,涡轮增压");
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
// 创建车对象(买了一辆车)
BMW2 bmw = new BMW2();
// 开动车
bmw.run(); // 父类的
bmw.run2(); // 自己的
}
}
上面的代码在运行的时候,发现BMW2中其实有两个运行的行为。run是从父类继承到的。而run2属于自己的。但是在真正调用的时候,也就是说可以选择两种不同的让车运动的行为。和实际不太符合。
这种情况下:一般我们会在子类中沿用父类的方法定义格式。然后将父类同名的方法的方法体全部在子类中重写。

子父类中同名的方法使用:
子类继承父类,当父类的功能子类也局部,但是功能体比父类更加强大(和父类不一致)的时候,子类可以在其中沿用父类的方法定义格式,重写方法体。
/*
* 过去的手机
*/
public class OldPhone {
public void call() {
System.out.println("打电话");
}
public void sendMessage() {
System.out.println("发短信");
}
}
/*
* 现在的手机
*/
public class NewPhone extends OldPhone{
/*
* 打电话功能:视频电话,来电显示、来电动画
*/
public void call(){
System.out.println("播放动画");
System.out.println("归属地");
System.out.println("打电话");
}
/*
* 发短信功能,新手机依然有发短信的功能,但是它可以在短信添加图片、音频,视频等信息
* 相当于子类可以延用父类的发短信功能的格式,但是需要对其进行功能的增强
*/
public void sendMessage(){
System.out.println("发短信");
System.out.println("发彩信");
}
}
3.6、super关键字
3.6.1、super关键字调用父类构造函数
super关键字,它主要用来在子类中调用父类的东西(成员变量、方法、构造方法)。
1、super( 实参 ) 在子类的构造函数中调用父类的构造函数
public class Person {
private String name;
private int age;
public Person(){}
// 在父类中添加一个构造函数,可以对name和age进行赋值操作
public Person(String name , int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/*
* Student类属于Person类中的一类
*/
public class Student extends Person{
// Student类在一创建的时候,就应该明确它的姓名和年龄
public Student( String name , int age ){
/*
* 在子类的构造函数中想使用父类中的name和age
* 表示当前这个学生的姓名和年龄
*
* 在子类的构造函数中需要调用父类的构造函数,才能完成
* 对父类中的name和age赋值
*/
super(name , age);
}
public void speak(){
System.out.println(getName() +":"+getAge());
}
}
/*
* 测试
*/
public class Test {
public static void main(String[] args) {
// 创建Student对象
Student s = new Student( "武状元" , 34 );
s.speak();
}
}

3.6.2、super父类和子类成员变量同名
2、super.成员变量名,表示在子类中使用父类公开的成员变量。
public class Demo1 {
int a = 123;
}
public class Demo2 extends Demo1{
int a = 456;
public void function(){
int a = 789;
System.out.println("打印局部变量a = " + a );
System.out.println("打印成员变量a = " + this.a );
System.out.println("打印父类成员变量a = " + super.a );
}
public static void main(String[] args) {
new Demo2().function();
}
}

注意:在static修饰的函数中也不能使用super,也不能使用this。
3.6.3、超级父类Object
在Java中任何一个类,如果没有使用extends关键字明确指出它的父类是谁,那么这个类的默认父类就是Object。Object类是Java中任何一个类的直接或者间接父类。它是Java中最顶层的类,它的上面再也没有其他的类了。Object类认为是Java中的上帝。Object类中的任何方法在任何的子类都可以使用。
如果在一个类的构造函数中不写super(实参)显示的指定调用父类的哪个构造函数,那么在这个类的任何一个构造函数内部都会默认有一个super();语句,它在调用父类哪个无参数的构造函数。

任何一个类中最后都会有某个构造函数里面会有一个super找父类的构造函数。最终它们会找到Object类中的空参数的构造函数。
this() 和super() 它们都必须放在构造函数中的第一行。因此一个构造函数中有this(),就不可能有super()。
3.7、final关键字
3.7.1、final介绍
final它的主要功能是用来修饰类、方法(函数)或变量(成员和局部)。
被final关键字修饰的类为最终类,不能被继承。
被final关键字修饰的函数,为最终还是,子类无法去复写。
被final修饰的变量,为最终值,这个变量中的数据永远无法改变。
3.7.2、使用场景
修饰类:
如果一个类不允许其他类继承,这时这个类必须使用final修饰。
修饰函数:
类如果没有被final修饰,这个类可以被继承,但是类中的某个函数被final修饰,子类不能去复写父类中当前被final修饰的这个类。但是父类中其他非final的函数依然可以被复写。
修饰变量:
被final修饰的变量空间中的值将无法改变。其实这个变量就相当于一个常量了。
因此要求:一般在开发中,如果某个变量被final修饰,这个变量名全部大写。
3.7.3、演示fianl使用



3.7.4、面试题
final修饰的变量是常量,final修饰的引用变量对应的对象中的数据能不能修改?

4、抽象类
4.1、什么是抽象类
抽象类:它依然是个类,也是在描述某类事物。只是在描述某个事物的行为特征的时候,可能发现不管怎么去书写它的行为体,都发现描述的不是特别的清晰(全)。这时我们可以将类中的这个行为描述成抽象行为。只要类中有了抽象行为,这个类就变成了抽象类。
抽象类:描述事物的时候,发现事物的行为没有办法描述具体,这时就可以使用抽象类表示当前这个事物。
4.2、抽象类演示
/**
* 员工类
*/
public abstract class Employee {
private String id;
private String name;
private String dept;
private double salay;
/*
* 员工都应用有工作的行为,但是发现这是公司里面的每个员工工作的内容都不相同
* 这是如果将工作的具体内容书写在员工类,那么导致子类继承之后,工作的行为全部一致。
* 现在我们只知道员工肯定有工作的行为,但是具体行为内容无法表达清楚。
* 这是可以使用Java中的抽象关键字来修饰当前这个函数。
*
* 注意:一个类中有了抽象函数,这个类就必须使用抽象关键字修饰。这个类就变成抽象类。
*/
public abstract void work();
}
// 描述动物的共性行为
public abstract class Animal {
/*
* 任何动物都具备eat行为,不同的动物,它们各自eat的内容不同
* 也就是说在Animal中我们可以知道的是有eat行为,但是eat的具体内容
* 却不能写的十分的清楚。
*
* 如果我们在描述事物的时候,发现某个事物的某个行为没有办法写具体
* 只是知道有这个行为,但是没有办法书写具体,可以使用Java中的抽象方法表示
* 这个不具体的行为。
*
* 抽象方法的定义格式:
* 修饰符 abstract 返回值类型 方法名 ( 参数列表 );
*/
public abstract void eat();
}
4.3、抽象的使用
如果一个类中有抽象方法,子类继承了这个类,要求子类必须去将父类中的所有抽象函数全部给复写掉。如果子类没有全部复写,就相当于子类从父类哪里继承到了抽象函数。这时就意味着子类中有隐式看不见的抽象函数,那么这个子类它依然也是一个抽象类。

4.4、抽象类的细节
1、一个类是抽象类,那么这个类不能创建对象。
因为如果类是抽象类,类中就有可能存在抽象方法,由于抽象方法是没有方法体。那么如果这个类可以创建对象,
那么就可能会调用到这个类中的抽象方法,那么抽象方法没有方法体,调用这样的方法根本就没有任何的意义。
2、抽象类中有没有构造函数?
有,虽然抽象类不能创建对象,但是它一定会子类,而子类中的构造函数中的隐式super会找父类的构造函数。
所以抽象类中的构造函数不是给自己用的,是给子类创建对象时候使用的。
3、抽象类一定是父类吗?
抽象肯定是父类,因为它必须有子类去复写其中的抽象函数。但不一定是最顶层的父类。
4、抽象类中可以没有抽象方法吗?
可以。如果一个类中一个抽象方法都没有,但是这个类却是抽象类,目的只有一个,就是不让创建这个类的对象。
这种用法主要用在适配器设计模式中。
5、abstract关键字不能和哪些关键字共存?
final:被final修饰的类不能被继承,被final修饰的方法不能被复写。但是abstract修饰的必须要求继承或复写。
private:被private修饰的函数,子类是根本继承不到的。但是abstract修饰的函数要求子类必须复写。
static:静态修饰的方法可以直接通过类名调用。但是abstract修饰的方法根本就没有方法体。调用就没有任何的意义。
抽象类:它依然是一个类,依然是在描述事物体系。只不过在描述事物体系的时候,发现某些行为不能描述具体。在抽象类中依然可以书写我们前面学习过的类中的任何的成员。大部分时候抽象会使用在多态技术中。我们经常使用抽象类的引用,指向自己的某个子类对象。
本文深入探讨Java中日期时间的处理,包括DateFormat与SimpleDateFormat类的使用,以及日期时间字符串的转换。同时,详细讲解了Java的继承机制,包括继承的概念、代码体现、细节、单继承与多继承的区别,以及抽象类的定义和使用。

7870

被折叠的 条评论
为什么被折叠?



