6--日期时间转换&继承&抽象类

本文深入探讨Java中日期时间的处理,包括DateFormat与SimpleDateFormat类的使用,以及日期时间字符串的转换。同时,详细讲解了Java的继承机制,包括继承的概念、代码体现、细节、单继承与多继承的区别,以及抽象类的定义和使用。

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修饰的方法根本就没有方法体。调用就没有任何的意义。

抽象类:它依然是一个类,依然是在描述事物体系。只不过在描述事物体系的时候,发现某些行为不能描述具体。在抽象类中依然可以书写我们前面学习过的类中的任何的成员。大部分时候抽象会使用在多态技术中。我们经常使用抽象类的引用,指向自己的某个子类对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QB哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值