day03【多态,内部类,常用API 1】
# 1 查看源码:ctrl+N
# 2 查看某个类的成员结构:alt+7
day03【多态,内部类,常用API 1】
-
多态(掌握)
-
内部类((掌握匿名内部类)
-
Object类(掌握)
-
时间日期类
-
DateFormat类
-
Calendar类
教学目标
- 能够说出使用多态的前提条件
- 理解多态的向上转型
- 理解多态的向下转型
- 说出内部类的概念
- 能够说出Object类的特点
- 能够重写Object类的toString方法
- 能够重写Object类的equals方法
- 能够使用Date类获取当前系统时间
- 能够使用DateFormat完成日期的格式化和解析
- 能够使用Calendar类的get、set、add方法操作日历时间
第一章 多态(必须掌握)
1.1 概述
引入
面向对象语言三大特征:封装(private)、继承(extends)、多态。
多态:表示的是一个事物的多种表现形态。同一个事物,以不同的形态表现出来.
多态来源于生活,在生活中我们经常会对某一类事物使用它的共性统称来表示某个具体的事物,这时这个具体的事物就以其他的形式展示出来。
苹果:说苹果,说水果。
狗:说狗,说动物。
猫:说猫,说动物。
前提【重点】
-
继承(extends)或者实现(implements)【二选一】
-
方法的重写【意义体现:不重写,无意义】
-
父类引用指向子类对象【格式体现】
1.2 多态的体现
多态体现的格式:
父类类型 变量名 = new 子类对象;
变量名.方法名();|
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
代码如下:
Fu f = new Zi();
f.method();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。
代码如下:
定义父类:
public abstract class Animal {
public abstract void eat();
}
定义子类:
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Animal a1 = new Cat();
// 调用的是 Cat 的 eat
a1.eat();
// 多态形式,创建对象
Animal a2 = new Dog();
// 调用的是 Dog 的 eat
a2.eat();
}
}
多态在代码中的体现为父类引用指向子类对象。
1.3 多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。代码如下:
定义父类:
public abstract class Animal {
public abstract void eat();
}
定义子类:
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat
showCatEat(c);
// 调用showDogEat
showDogEat(d);
/*
以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
而执行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当然可以把Cat对象和Dog对象,传递给方法。
当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致,所以showAnimalEat完全可以替代以上两方法。
不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用showAnimalEat都可以完成。
所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。
小结:多态的好处是提高程序的灵活性,扩展性
1.4 引用类型转换
多态的转型分为向上转型与向下转型两种:
向上转型
-
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。
使用格式:
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
向下转型
-
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a;
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类有而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
转型演示,代码如下:
定义类:
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watchHouse() {
System.out.println("看家");
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
}
}
转型的异常
转型的过程中,一不小心就会遇到这样的问题,请看如下代码:
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
}
}
这段代码可以通过编译,但是运行时,却报出了 ClassCastException
,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。
为了避免ClassCastException的发生,Java提供了 instanceof
关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。
所以,转换前,我们最好先做一个判断,代码如下:
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
小结:多态向上转型是将子类类型转成父类类型,多态向下转型是将父类类型转成子类类型。
1.5笔记本案例
-
案例目的:接口也可以体现多态
-
案例代码:
USB接口:
/*
* 定义一个USB接口
*/
public interface USB {
public void open();
public void close();
}鼠标类:
/*
* 定义一个鼠标类
*/
public class Mouse implements USB{
//行为:开启
public void open()
{
System.out.println("mouse open....");
}
//行为:关闭
public void close()
{
System.out.println("mouse close....");
}
}键盘类:
/*
* 定义一个键盘类
*/
public class Keyboard implements USB{
// 行为:开启
public void open() {
System.out.println("keyboard open....");
}
// 行为:关闭
public void close() {
System.out.println("keyboard close....");
}
}电脑类:
/*
* 描述电脑类
*/
public class Computer {
//属性
//行为
public void run()
{
System.out.println("computer run....");
}
//给电脑外围设备提供预留的功能,该功能要遵守USB接口的规则
public void useUSB(USB u)//USB u=m
{
if(u!=null)
{
u.open();
u.close();
}
}
}测试类:
public class ComputerTest {
public static void main(String[] args) {
// 创建笔记本电脑类的对象
Computer c = new Computer();
c.run();
Mouse m = new Mouse();
//电脑使用鼠标
c.useUSB(m);
Keyboard k = new Keyboard();
// //电脑使用键盘
c.useUSB(k);
}
}总结:发现接口的出现:
1、 扩展了笔记本电脑的功能.
2、 定义了规则.
3、降低了笔记本电脑和外围设备之间的耦合性.
解耦
第二章 内部类
2.1 概述
2.1.1 什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。可以把内部类理解成寄生,外部类理解成宿主。
内部类是Java类的五大成员之一,也是我们最后一个需要学习的成员。
2.1.2 什么时候使用内部类
一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用
-
人里面有一颗心脏。
-
汽车内部有一个发动机。
-
为了实现更好的封装性。
2.2 内部类的分类
按定义的位置来分
-
成员内部类,类定义在了成员位置 (类中方法外称为成员位置)
-
匿名内部类。定义在局部位置
2.3 成员内部类
成员内部类特点:
-
无static修饰的内部类,属于外部类对象的。
-
宿主:外部类对象。
内部类的使用格式:
外部类.内部类。 // 访问内部类的类型都是用 外部类.内部类
实例内部类创建对象格式:
外部类.内部类 变量 = new 外部类构造器.new 内部类构造器;
案例演示
class Outer02{
// 实例内部类,属于外部类对象的。
// 拓展:实例内部类不能定义静态成员。
public class Inner02{
// 这里面的东西与类是完全一样的。
private String name;
public Inner02(String name) {
this.name = name;
}
public void showName(){
System.out.println(this.name);
}
}
}
public class InnerClassDemo02 {
public static void main(String[] args) {
// 宿主:外部类对象。
// Outer02 out = new Outer02();
// 创建内部类对象。
Outer02.Inner02 in = new Outer02().new Inner02("张三");
in.showName();
}
}
Outer.Inner in=new Outer().new Inner();表示使用外部类的匿名对象new Outer()调用内部类的对象重新赋值给一个变量in。这里的in就表示内部类对象名。
注意:上述代码中,当外部类Outer.class被加载到内存中的时候,内部类Outer$Inner.class还没有被加载到内存中,仍然在硬盘中,只有当创建对象的时候使用内部类的时候,jvm才会将Outer$Inner.class加载到内存中。
2.4 成员内部类面试题
注意:内部类访问外部类对象的格式是:外部类名.this
// 身体
class Body {
private int weight = 30;
// 在成员位置定义一个类
class Heart {
private int weight = 20;
public void jump() {
System.out.println("局部内部类函数this="+this);
System.out.println("外部类this="+Body.this);
int weight = 10;
System.out.println("心脏在跳动 " + weight); // 10
System.out.println("心脏在跳动 " + this.weight); // 20
System.out.println("心脏在跳动 " + Body.this.weight); // 30
}
}
}
public class Demo05 {
public static void main(String[] args) {
Body b = new Body();
System.out.println("b="+b);
Body.Heart heart = new Body().new Heart();
System.out.println("heart="+heart);
heart.jump();
}
}
2.5 匿名内部类【重点】
2.5.1 概述
匿名内部类 :是内部类的简化写法。它的本质是一个带具体实现的
父类或者父接口的
匿名的
子类对象。 开发中,最常用到的内部类就是匿名内部类了。
2.5.2 引入
实际上,如果我们希望定义一个只要使用一次的类,就可考虑使用匿名内部类。匿名内部类的本质作用
是为了简化代码。
之前我們使用接口时,似乎得做如下几步操作:
-
定义子类
-
重写接口中的方法
-
创建子类对象
-
调用重写后的方法
interface Swim {
public abstract void swimming();
}
// 1. 定义接口的实现类
class Student implements Swim {
// 2. 重写抽象方法
@Override
public void swimming() {
System.out.println("狗刨式...");
}
}
public class Demo07 {
public static void main(String[] args) {
// 3. 创建实现类对象
Student s = new Student();
// 4. 调用方法
s.swimming();
}
}
我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。
2.5.3 匿名内部类前提和格式
匿名内部类必须继承一个父类或者实现一个父接口。
匿名内部类格式
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
说明:
1.其实上述整体格式是父类或者父接口的子类对象
2.
{
// 方法重写
@Override
public void method() {
// 执行语句
}
}
这些内容称为匿名内部类。但是不能单独书写,必须结合上述new 父类名或者接口名()一起。
2.5.4 使用方式
以接口为例,匿名内部类的使用,代码如下:
创建匿名内部类。
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 使用匿名内部类
new Swim() {
@Override
public void swimming() {
System.out.println("自由泳...");
}
}.swimming();
// 接口 变量 = new 实现类(); // 多态,走子类的重写方法
Swim s2 = new Swim() {
@Override
public void swimming() {
System.out.println("蛙泳...");
}
};
s2.swimming();
}
}
2.5.5 匿名内部类的特点
-
定义一个没有名字的内部类
-
这个类实现了父类,或者父类接口
-
匿名内部类会创建这个没有名字的类的对象
2.5.6 匿名内部类的使用场景
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 普通方式传入对象
// 创建实现类对象
Student s = new Student();
goSwimming(s);
// 匿名内部类使用场景:作为方法参数传递
Swim s3 = new Swim() {
@Override
public void swimming() {
System.out.println("蝶泳...");
}
};
// 传入匿名内部类
goSwimming(s3);
// 完美方案: 一步到位
goSwimming(new Swim() {
public void swimming() {
System.out.println("大学生, 蛙泳...");
}
});
goSwimming(new Swim() {
public void swimming() {
System.out.println("小学生, 自由泳...");
}
});
}
// 定义一个方法,模拟请一些人去游泳
public static void goSwimming(Swim s) {
s.swimming();
}
}
第三章 Object类
3.1 概述
java.lang.Object
类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。
如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:
public class MyClass /*extends Object*/ {
// ...
}
根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。今天我们主要学习其中的2个:
-
public String toString()
:返回该对象的字符串表示。 -
public boolean equals(Object obj)
:指示其他某个对象是否与此对象“相等”。
3.2 toString方法
方法摘要
-
public String toString()
:返回该对象的字符串表示。
toString方法返回该对象的字符串表示,其实该字符串内容就是:对象的类型名+@+内存地址值。
由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
-
输出语句:
-
在输出语句中打印对象时,会自动调用对象的toString()方法
public class Demo04测试类 {
public static void main(String[] args) {
//创建对象
Student s = new Student("柳岩",22);
//在输出语句中打印对象时,会自动调用对象的toString()方法
System.out.println(s);
System.out.println(s.toString());
}
} -
-
查看源码:
-
Object类中的toString方法:全类名 + "@" + 十六进制的地址值表示
public String toString() {
// 全类名 + "@" + 十六进制的地址值表示
return getClass().getName() + "@" + Integer.toHexString(hashCode());
} -
-
使用idea完成方法重写:
-
父类中toString()是地址值,没有意义。
-
在子类中重写toString()的目的是在获取时看到对象的成员变量的值。
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
} -
在IntelliJ IDEA中,可以点击Code
菜单中的Generate...
,也可以使用快捷键alt+insert
,点击toString()
选项。选择需要包含的成员变量并确定。
小贴士: 在我们直接使用输出语句输出对象名的时候,其实通过该对象调用了其toString()方法。
小结:toString方法可以将对象转成字符串。
3.3 equals方法
方法摘要
-
public boolean equals(Object obj)
:指示其他某个对象是否与此对象“相等”。
调用成员方法equals并指定参数为另一个对象,则可以判断这两个对象是否是相同的。
-
回顾==号:
public class Demo{
public static void main(String[] args) {
int a = 10;
int b = 10;
Student s1 = new Student("柳岩",36);
Student s2 = new Student("柳岩",36);
//==判断基本类型判断的是值是否相等
System.out.println(a == b); //true
//==判断引用类型判断的是地址值是否相等
System.out.println(s1 == s2); //false
boolean boo = s1.equals(s2);
System.out.println(boo);
}
} -
查看源码:
-
Object类中的equals()方法也是判断地址值是否相同
public boolean equals(Object obj) {
return (this == obj);
}
-
-
idea重写equals()方法的解析:
-
因为父类中的方法没有意义。
-
子类中重写equals()方法的目的是为了判断对象的内容是否相同。
@Override
//重写之后equals()作用就是判断对象的内容是否相同
public boolean equals(Object o) {
//this相当于s1 o相当于s2
//如果两个对象地址值相同,那么内容一定相同
if (this == o){
return true;
}
// 如果参数不为空,判断两个对象是否是同种类型,如果类型不同直接返回false
/*
1.o == null 判断参数o是否为null,如果为null直接返回false
2.getClass() != o.getClass() :getClass()相当于this.getClass()表示调用者的类型,o.getClass()表示参数类型,如果类型不同直接返回false
*/
if (o == null || getClass() != o.getClass()){
return false;
}
//如果程序能走到这里就说明两个对象类型是相同的
//向下转型
Student student = (Student) o;
//判断年龄和姓名是否相同
return age == student.age &&
Objects.equals(name, student.name);
} -
这段代码充分考虑了对象为空、类型一致等问题,但方法内容并不唯一。大多数IDE都可以自动生成equals方法的代码内容。在IntelliJ IDEA中,可以使用Code
菜单中的Generate…
选项,也可以使用快捷键alt+insert
,并选择equals() and hashCode()
进行自动代码生成。
tips:Object类当中的hashCode等其他方法,今后学习。
小结:equals方法可以判断两个对象是否相同,如果要定义自己的比较规则,需要进行重写。
3.4 native本地方法
在Object类的源码中定义了 native 修饰的方法, native 修饰的方法称为本地方法。
本地方法的作用: 就是Java调用非Java代码的接口。方法的实现由非Java语言实现,比如C或 C++。
比如:
被native修饰的本地方法我们无法查看源码。
public native int hashCode();
第四章 Objects类
在刚才IDEA自动重写equals代码中,使用到了java.util.Objects
类,那么这个类是什么呢?
在JDK7添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)。
在比较两个对象的时候,Object的equals方法容易抛出空指针异常,而Objects类中的equals方法就优化了这个问题。方法如下:
-
Objects的equals()源码解析:
-
作用:
Objects的equals()是一个静态方法,可以使用类名直接调用,可以更完善的判断两个对象。
-
源码:
/*
源码的内部其实也是使用equals()方法在判断
只不过在判断之前做了一些更完善的操作:
1.先判断两个对象的地址值是否相同,如果相同就会短路,提高效率
2.判断a不等于null,避免空指针异常
*/
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
} -
优点:
提高效率,避免了异常的产生。
-
代码演示:
package com.itheima.sh.demo_03;
import java.util.Objects;
public class Test01 {
public static void main(String[] args) {
//定义一个字符串
String s1 = null;
String s2 = "abc";
//判断s1和s2是否相等 NullPointerException
// boolean boo = s1.equals(s2);
/*
防止空指针异常引入Objects类,从jdk1.7 真正是在jdk1.8开始使用
static boolean equals(Object a, Object b)
*/
//使用Objects工具类中的静态方法比较上述s1和s2,目的是防止空指针异常
// boolean boo = Objects.equals(s1, s2);
/*
Object a= s2 --- "abc" 发生多态了
Object b = s1 --- null
public static boolean equals(Object a, Object b) {
//a属于String类对象,调用Object的子类String类中的equals方法
return (a == b) || (a != null && a.equals(b));
}
*/
boolean boo = Objects.equals(s2, s1);
System.out.println("boo = " + boo);
}
}
第五章 Date类
5.1概述
java.util.Date
类 表示特定的瞬间,精确到毫秒。
继续查阅Date类的描述,发现Date拥有多个构造函数,只是部分已经过时,我们重点看以下两个构造函数
-
public Date()
:从运行程序的此时此刻到时间原点经历的毫秒值,转换成Date对象,分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。 -
public Date(long date)
:将指定参数的毫秒值date,转换成Date对象,分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970年1月1日00:00:00 GMT)以来的指定毫秒数。
tips: 由于中国处于东八区(GMT+08:00)是比世界协调时间/格林尼治时间(GMT)快8小时的时区,当格林尼治标准时间为0:00时,东八区的标准时间为08:00。
简单来说:使用无参构造,可以自动设置当前系统时间的毫秒时刻;指定long类型的构造参数,可以自定义毫秒时刻。例如:
import java.util.Date;
public class Demo01Date {
public static void main(String[] args) {
// 创建日期对象,把当前的时间
System.out.println(new Date()); // Tue Jan 16 14:37:35 CST 2020
// 创建日期对象,把当前的毫秒值转成日期对象
System.out.println(new Date(0L)); // Thu Jan 01 08:00:00 CST 1970
}
}
tips:在使用println方法时,会自动调用Date类中的toString方法。Date类对Object类中的toString方法进行了覆盖重写,所以结果为指定格式的字符串。
5.2 常用方法
Date类中的多数方法已经过时,常用的方法有:
-
public long getTime()
把日期对象转换成对应的时间毫秒值。 -
public void setTime(long time)
把方法参数给定的毫秒值设置给日期对象
示例代码
public class DateDemo02 {
public static void main(String[] args) {
//创建日期对象
Date d = new Date();
//public long getTime():获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
//System.out.println(d.getTime());
//public void setTime(long time):设置时间,给的是毫秒值
long time = 1000*60*60;
d.setTime(time);
System.out.println(d);
}
}
小结:Date表示特定的时间瞬间,我们可以使用Date对象对时间进行操作。
第六章 DateFormat类
6.1概述
java.text.DateFormat
是日期/时间格式化子类的抽象类,我们通过这个类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。
-
格式化:按照指定的格式,把Date对象转换为String对象。
-
解析:按照指定的格式,把String对象转换为Date对象。
6.2 构造方法
由于DateFormat为抽象类,不能直接使用,所以需要常用的子类java.text.SimpleDateFormat
。这个类需要一个模式(格式)来指定格式化或解析的标准。构造方法为:
-
public SimpleDateFormat(String pattern)
:用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat。参数pattern是一个字符串,代表日期时间的自定义格式。
6.3 格式规则
常用的格式规则为:
标识字母(区分大小写) | 含义 |
---|---|
y | 年 |
M | 月 |
d | 日 |
H | 时 |
m | 分 |
s | 秒 |
备注:更详细的格式规则,可以参考SimpleDateFormat类的API文档。
6.4 常用方法
DateFormat类的常用方法有:
-
public String format(Date date)
:将Date对象格式化为字符串。 -
public Date parse(String source)
:将字符串解析为Date对象。public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
//格式化:从 Date 到 String
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);
System.out.println("--------");
//从 String 到 Date
String ss = "2048-08-09 11:11:11";
//ParseException
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dd = sdf2.parse(ss);
System.out.println(dd);
}
}
小结:DateFormat可以将Date对象和字符串相互转换。
6.5练习
练习一:字符串日期的格式转化
键盘输入一个日期:2008年8月8日 需求:变成"2008/8/8"的格式
public class Test01 {
/*
键盘输入一个日期:2008年8月8日
需求:变成"2008/8/8"的格式
*/
public static void main(String[] args) throws ParseException {
//1.键盘输入字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个日期:格式(2008年8月8日)");
String s = sc.nextLine();
//2.把字符串转成日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(s);
//3.把日期转成另一个格式的字符串
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd");
String s2 = sdf2.format(date);
System.out.println("转换后" + s2);
}
}
练习二:求你来到这个世界多少天?
键盘输入一个字符串类型的时间,打印来到世界多少天。
比如:
请输入你的出生时间: 1999-01-01
你来到这个世界已经8888天了
public class Test02 {
public static void main(String[] args) throws ParseException {
//你来到这个世界多少天了?
//1.键盘输入字符串类型的时间
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的出生年月日:(格式:2008年8月8日)");
String birth = sc.nextLine();
//2.把字符串时间转成日期类型
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date birthDate = sdf.parse(birth);
//3.获取当前时间
Date nowDate = new Date();
//4.获取日期对象的毫秒值
long time1 = birthDate.getTime();
long time2 = nowDate.getTime();
//5.毫秒值计算成天数
System.out.println("你已经活了" + ((time2-time1)/1000/60/60/24) + "天了");
}
}
第七章 Calendar类
7.1 概述
概述:
-
java.util.Calendar类表示一个“日历类”,可以进行日期运算。
-
日历类把和时间相关的所有值都定义为了字段,对时间的操作可以用字段的方式完成。
-
它是一个抽象类,不能创建对象,我们可以使用它的子类:java.util.GregorianCalendar类。
-
有两种方式可以获取GregorianCalendar对象:
-
直接创建GregorianCalendar对象;子类构造方法:
GregorianCalendar()
-
通过Calendar的静态方法getInstance()方法获取GregorianCalendar对象【本次课使用】
-
7.2 常用方法
方法名 | 说明 |
---|---|
public static Calendar getInstance() | 获取一个它的子类GregorianCalendar对象。 |
public int get(int field) | 获取某个字段的值。field参数表示获取哪个字段的值, 可以使用Calender中定义的常量来表示: Calendar.YEAR : 年 Calendar.MONTH :月 Calendar.DAY_OF_MONTH:月中的日期 Calendar.HOUR:小时 Calendar.MINUTE:分钟 Calendar.SECOND:秒 Calendar.DAY_OF_WEEK:星期 |
public void set(int field,int value) | 设置某个字段的值 |
public void add(int field,int amount) | 为某个字段增加/减少指定的值 |
setTime(Date date) | 把Date对象转成Calendar对象 |
7.3 get方法示例
说明:DAY_OF_WEEK的范围:1--7,分别表示:"星期日","星期一","星期二",...,"星期六"。在java中,星期日是一周的第一天。
// 1 2 3 4 5 6 7
// 日 一 二 三 四 五 六
public class Demo {
public static void main(String[] args) {
//1.获取一个GregorianCalendar对象
Calendar instance = Calendar.getInstance();//获取子类对象
//2.打印子类对象
System.out.println(instance);
//3.获取属性
int year = instance.get(Calendar.YEAR);
int month = instance.get(Calendar.MONTH) + 1;//Calendar的月份值是0-11
int day = instance.get(Calendar.DAY_OF_MONTH);
int hour = instance.get(Calendar.HOUR);
int minute = instance.get(Calendar.MINUTE);
int second = instance.get(Calendar.SECOND);
System.out.println(year + "年" + month + "月" + day + "日" +
hour + ":" + minute + ":" + second);
int week = instance.get(Calendar.DAY_OF_WEEK);//返回值范围:1--7,分别表示:"星期日","星期一","星期二",...,"星期六"
// 在java中,星期日是一周的第一天
System.out.println("星期:" + method(week));
// 1 2 3 4 5 6 7
// 日 一 二 三 四 五 六
}
//把Calendar中的星期转成我们中国习惯的星期
public static String method(int week){
//创建数组
String[] arr = {"","日","一","二","三","四","五","六"};
//返回元素
return arr[week];
}
}
7.4 set和add方法示例
package com.itheima.sh.k_date_11;
import java.util.Calendar;
/*
Calendar类中的set add方法演示
*/
public class CalendarDemo07 {
public static void main(String[] args) {
//1.创建Calendar类的对象
Calendar c = Calendar.getInstance();
//2.修改年
// c.set(Calendar.YEAR,1999);
// //获取 1999
// System.out.println(c.get(Calendar.YEAR));
//3.将当前的年-100
// c.add(Calendar.YEAR,-100);
// System.out.println(c.get(Calendar.YEAR));//1921
//4.设置月份的值为4
// c.set(Calendar.MONTH,4);
// System.out.println(c.get(Calendar.MONTH));
//5.给月份+1
/*c.add(Calendar.MONTH,1);
System.out.println(c.get(Calendar.MONTH)+1);//目前是3月份,+1后就是4月份*/
/*
扩展:
如果月份超过范围修改年份,天数超过范围修改月份
*/
c.add(Calendar.MONTH,-3);
System.out.println(c.get(Calendar.YEAR)+"---"+(c.get(Calendar.MONTH)+1));//
}
}
7.5 setTime(Date date)方法演示
void setTime(Date date) 使用给定的 Date 设置此 Calendar 的时间。
/*
void setTime(Date date) 使用给定的 Date 设置此 Calendar 的时间。
*/
public class Test02 {
public static void main(String[] args) {
//创建日历
Calendar c = Calendar.getInstance();
//获取年
int year = c.get(Calendar.YEAR);
//没有更改c表示的内容,获取的是当前时间
System.out.println(year); //2020
//创建日期对象
Date d = new Date(3181277292010L);
System.out.println(d);
//把Date所表示的时间赋值给Calender
//void setTime(Date date) 使用给定的 Date 设置此 Calendar 的时间。
c.setTime(d);
//获取年
int year2 = c.get(Calendar.YEAR);
//更改之后c表示的内容,获取的是当前时间
System.out.println(year2); //2070
}
}
第八章 Math类
1 概述
-
java.lang.Math(类): Math包含执行基本数字运算的方法。
-
它不能创建对象,它的构造方法被“私有”了。因为他内部都是“静态方法”,通过“类名”直接调用即可。
2 常用方法
方法名 | 说明 |
---|---|
public static int abs(int a) | 获取参数a的绝对值: |
public static double ceil(double a) | 向上取整 |
public static double floor(double a) | 向下取整 |
public static double pow(double a, double b) | 获取a的b次幂 |
public static long round(double a) | 四舍五入取整 |
3 示例代码
public class Demo {
public static void main(String[] args) {
System.out.println("-5的绝对值:" + Math.abs(-5));//5
System.out.println("3.4向上取整:" + Math.ceil(3.4));//4.0
System.out.println("3.4向下取整:" + Math.floor(3.4));//3.0
System.out.println("2的8次幂:" + Math.pow(2, 8));//256.0
System.out.println("3.2四舍五入:" + Math.round(3.2));//3
System.out.println("3.5四舍五入:" + Math.round(3.5));//4
}
}
第九章 System
1 概述
java.lang.System
类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作。
2 常用方法
方法名 | 说明 |
---|---|
public static void exit(int status) | 终止当前运行的 Java 虚拟机,非零表示异常终止 |
public static long currentTimeMillis() | 返回当前时间(以毫秒为单位) |
static void arrayCopy() | 数组中元素的复制 |
代码演示:
public class Demo02{
public static void main(String[] args) {
//退出虚拟机
//System.exit(0);
//获取当前时间的毫秒值
long time1 = System.currentTimeMillis();
System.out.println(time1);
//Date
Date d = new Date();
long time2 = d.getTime();
System.out.println(time2);
//数组中元素的复制
int[] arr = {11,22,33,44,55,66};
int[] brr = {0,0,0,0,0,0};
/*
复制数组的方法:
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
参数:
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目标数据中的起始位置。
length - 要复制的数组元素的数量。
*/
System.arraycopy(arr,2,brr,0,3);
//打印数组查看结果
for (int i = 0; i < brr.length; i++) {
System.out.print(brr[i] + " ");
}
// brr : 33 44 55 0 0 0
System.out.println();
System.out.println("------------------------------");
//练习
System.arraycopy(brr,0,brr,2,2);
//打印数组查看结果
for (int i = 0; i < brr.length; i++) {
System.out.print(brr[i] + " ");
}
// 33 44 33 44 0 0
}
}