主要内容
- Object类
- Date类
- DateFormat类
- Calendar类
1.Object类
1.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)
:指示其他某个对象是否与此对象“相等”。
1.2 toString方法
-
public String toString()
:返回该对象的字符串表示。
toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。
由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
Person类:
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// 省略构造器与Getter Setter
}
在IntelliJ IDEA中,可以点击Code
菜单中的Generate...
,也可以使用快捷键alt+insert
,点击toString()
选项。选择需要包含的成员变量并确定。生成的重写方法toString方法就类似于上边的方法。
小贴士: 在我们直接使用输出语句输出对象名的时候,其实通过该对象调用了其toString()方法。如果输出的内容为一个地址值,那么该类没有重写toString,否则,就重写了toString方法。
那么接下来就可以试验一下哪些方法重写了toString,哪些方法没有重写toString。
Person类:
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/*
直接打印对象的地址值没有意义,需要重写Object类中的toString方法
打印对象的属性(name,age)
*/
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//getter和setter省略
Main类:
public class Demo01ToString{
public static void main(String[] args) {
/*
Person类默认继承了Object类,所以可以使用Object类中的toString方法
String toString() 返回该对象的字符串表示。
*/
Person p = new Person("张三",18);
String s = p.toString();
System.out.println(s);//com.itheima.demo01.Object.Person@75412c2f | abc | Person{name=张三 ,age=18}
//直接打印对象的名字,其实就是调用对象的toString p=p.toString();
System.out.println(p);//com.itheima.demo01.Object.Person@5f150435 | abc | Person{name=张三 ,age=18}
//看一个类是否重写了toString,直接打印这个类的对象即可,如果没有重写toString方法那么打印的是对象的地址值
Random r = new Random();
System.out.println(r);//java.util.Random@3f3afe78 没有重写toString方法
Scanner sc = new Scanner(System.in);
System.out.println(sc);//java.util.Scanner[delimiters=\p{javaWhitespace}+.. 重写toString方法
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);//[1, 2, 3] 重写toString方法
}
}
- Random类中就没有重写toString方法
- Scanner类重写了toString方法
- ArrayList也重写了toString方法
1.3 equals方法
1.Object类中的Equals()
Person类默认继承了Object类,所以可以使用Object类的equals方法.
public boolean equals(Object obj)
:指示其他某个对象是否与此对象“相等”。
equals方法源码:
public boolean equals(Object obj) {
return (this == obj);
}
- 参数:Object obj:可以传递任意的对象
- 返回值:
==
比较运算符,返回的是一个布尔值 true false - 基本数据类型:比较的是值
- 引用数据类型:比价的是两个对象的地址值
举例:
Person类:
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter和setter省略
}
MainEquals:
public class Demo02Equals {
public static void main(String[] args) {
Person p1 = new Person("迪丽热巴",18);
//Person p2 = new Person("古力娜扎",19);
Person p2 = new Person("迪丽热巴",18);
System.out.println("p1:"+p1);//p1:com.itheima.demo01.Object.Person@58ceff1
System.out.println("p2:"+p2);//p2:com.itheima.demo01.Object.Person@7c30a502
boolean b = p1.equals(p2); //调用Object类中的Equals方法,this为p1,obj为p2
System.out.println(b); //false
对应源码:
this是谁?
- 那个对象调用的方法,方法中的this就是那个对象;p1调用的equals方法所以this就是p1。
obj是谁?- 传递过来的参数p2
返回为false,因为引用类型比较地址值。
在创建对象p1和p2后,加上一段:
p1 = p2
那么代码结果为true,因为p2 的地址值也是p1的地址值。
2.重写Object类的Equals方法
Object类的equals方法,默认比较的是两个对象的地址值,没有意义。
所以我们要在Person类中重写equals方法,比较自己想要比较的内容:
例如:
比较两个对象的属性(name,age)
问题:
我们观察Object类中的Equals方法的参数,类型为Object。
这里隐含着一个多态,发生了向上转型--Person-->Objetct。
- 那么多态的弊端:无法使用子类特有的内容(属性 和方法)。
Object obj = p2 = new Person("古力娜扎",19);
- 解决:可以使用向下转型(强转)把obj类型转换为Person。
所以我们在Person类中重写Equals方法时,参数类型如果为Object的话,要进行判断参数的类型,因为Object类时所有类的父类,我们不知道Object类创建的对象是哪个类。
Person类--Equeals():
public boolean equals(Object obj) {
//增加一个判断,传递的参数obj如果是this本身,直接返回true,提高程序的效率
if(obj==this){
return true;
}
//增加一个判断,传递的参数obj如果是null,直接返回false,提高程序的效率
if(obj==null){
return false;
}
//增加一个判断,防止类型转换一次ClassCastException
if(obj instanceof Person){
//使用向下转型,把obj转换为Person类型
Person p = (Person)obj;
//比较两个对象的属性,一个对象是this(p1),一个对象是p(obj->p2)
boolean b = this.name.equals(p.name) && this.age==p.age;
return b;
}
//不是Person类型直接返回false
return false;
在该方法中充分考虑了参数对象为空、参数为本身等问题,如果对象类型为Person类,那么就向下转型为Person类,就可以调用该类的属性和方法了,进而就可以判断该类的age和name和本类是否一致。
可以使用快捷键
alt+insert
,并选择equals() and hashCode()
进行自动代码生成,
tips:Object类当中的hashCode等其他方法,今后学习。
自动生成的代码:
@Override
public boolean equals(Object o) {
if (this == o) return true;
//getClass() != o.getClass() 使用反射技术,判断o是否是Person类型 等效于 obj instanceof Person
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
流程与上述代码大概一致,但是子啊比较的时候使用Objects.equals()
不太明白,下一节讲Object类的静态方法Equals()。
1.4 Object类中的静态方法Equals()
Objects类的equals方法:对两个对象进行比较,防止空指针异常。
equals()源码:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
该方法可有效的防止比较对象为空时报错的情况。
DemoObjects类:
public class Demo03Objects {
public static void main(String[] args) {
String s1 = "abc";
// String s1 = null;
String s2 = "abc";
boolean b = s1.equals(s2); // NullPointerException null是不能调用方法的,会抛出空指针异常
System.out.println(b);
//s1,s2为引用类型,只不过String类重写了toString方法,s1=s2=“abc”
boolean b2 = Objects.equals(s1, s2);
System.out.println(b2);
}
}
- 当s1和s2都为“abc”时,因为使用s1.Equals(s2)和Object.Equals(s1,s2)是一样的。
- 当s1为空时,在使用该空对象s1调用Equals(s2),报出NullPointerException (空指针异常),而调用Object.equals(s1=null,s2)不会报错。
- 问题:equals()对于引用类型比较的应该是地址值,那么我们创建了两个String类对象,理论上应该地址值是不同的,但是由于String类常量池的存在,所以s1和s2指向的地址是相同的。
1.5Object类方法总结
1.toString()方法
- 作用:打印对象信息
- 重写前:打印的是包名类名@地址值
- 重写后;打印的是对象自定义的内容
2.equals()方法
- 作用:比较两个对象
- 重写前:比价两个对象的地址值(Object类)
- 重写后:比较类中自定义的内容
3.Objec类中静态equals()
- 作用:比较两个对象是否相同。
只是加了一些健壮性操作,防止空指针异常。
2.日期时间类
-
java.util.Date:表示日期和时间的类,类 Date 表示特定的瞬间,精确到毫秒。
-
毫秒:千分之一秒 1000毫秒=1秒
特定的瞬间:一个时间点,一刹那时间。 -
时间原点(0毫秒):
1970 年 1 月 1 日 00:00:00(英国格林威治)。 -
把毫秒转换为日期:
1 天 = 24 × 60 × 60 = 86400 秒 = 86400 x 1000 = 86400000毫秒 -
毫秒值的作用:可以对时间和日期进行计算,例如:2099-01-03 到 2088-01-01 中间一共有多少天?
可以日期转换为毫秒进行计算,计算完毕,在把毫秒转换为日期。
注意:
中国属于东八区,会把时间增加8个小时,也就是1970 年 1 月 1 日 08:00:00
2.1Date类
Date拥有多个构造函数,只是部分已经过时
1.构造方法
1.空参数构造方法:获取当前系统的时间
/*
Date类的空参数构造方法
Date() 获取当前系统的日期和时间
*/
private static void demo01() {
Date date = new Date();
System.out.println(date);//Fri Aug 21 22:58:31 CST 2020
}
public static void main(String[] args) {
demo01();
}
2.带参数的构造方法:传入long类型的毫秒值,返回对应日期。
/*
Date类的带参数构造方法
Date(long date) :传递毫秒值,把毫秒值转换为Date日期
*/
private static void demo02() {
Date date = new Date(0L);
System.out.println(date);// Thu Jan 01 08:00:00 CST 1970
date = new Date(3742767540068L);
System.out.println(date);// Sun Aug 08 09:39:00 CST 2088
}
public static void main(String[] args) {
demo02();
}
2.成员方法
1.成员方法getTime():获取当前日期对应的毫秒值(Long类型)
/*
long getTime() 把日期转换为毫秒值(相当于System.currentTimeMillis()方法)
返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
*/
private static void demo03() {
Date date = new Date();
long time = date.getTime(); //获取当前日期对应的毫秒值
System.out.println(time); //3742777636267
}
public static void main(String[] args) {
demo03();
}
2.2DateFormat类
java.text.DateFormat
是日期/时间格式化子类的抽象类,我们通过这个类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。
- 格式化:按照指定的格式,从Date对象转换为String对象。
- 解析:按照指定的格式,从String对象转换为Date对象。
1.构造方法
由于DateFormat为抽象类,不能直接使用,所以需要创建常用的子类java.text.SimpleDateFormat
的对象来使用。
这个类的构造方法需要一个模式(格式)来指定格式化或解析的标准。构造方法为:
-
public SimpleDateFormat(String pattern)
:用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat。
- 参数pattern是一个字符串,代表日期时间的自定义格式。
2.格式规则
常用的格式规则为:
标识字母(区分大小写) | 含义 |
---|---|
y | 年 |
M | 月 |
d | 日 |
H | 时 |
m | 分 |
s | 秒 |
备注:更详细的格式规则,可以参考SimpleDateFormat类的API文档0。
写对应的模式,会把模式替换为对应的日期和时间
例如:"yyyy-MM-dd HH:mm:ss"
- 注意:
模式中的字母不能更改,连接模式的符号可以改变
"yyyy年MM月dd日 HH时mm分ss秒"
3.SimpleDateFormat构造方法的使用
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
DateFormat obj = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
}
}
传入后没有任何输出,只是在之后的使用中会起到限定格式的作用。
4.format方法
public String format(Date date)
:将Date对象格式化为字符串。
Test:
public class Test {
public static void main(String[] args) {
// 1.创建SimpleDateFormat对象,在构造中设置格式
DateFormat obj = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
// 2.获取当前时间(无格式)
Date data = new Date();
System.out.println(data); //Sat Aug 22 23:15:42 CST 2020
// 3.调用format()继续宁转换
String str = obj.format(data);
System.out.println(str); //2020-08-22 23-16-48
}
}
5.parse方法
public Date parse(String source)
:将字符串解析为Date对象。
public class Test {
public static void main(String[] args) throws ParseException {
// 1.创建SimpleDateFormat对象,在构造中设置格式
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
// 2.生成与构造方法中格式一致的时间格式
String str = "2020-08-22 23-16-56";
// 3.调用parse转换为Data类型
Date data = df.parse(str);
System.out.println(data); //Sat Aug 22 23:16:56 CST 2020
}
}
在使用parse的过程中,会报出错误,原因是在该类parse方法的内部使用了异常捕获,所以我们在使用是也要异常捕获,alt+Enter选择第一个选项--在该方法中加上异常捕获,或者选择第二个,try-catch捕获异常。
2.3时间日期练习
请使用日期时间相关的API,计算出一个人已经出生了多少天。
思路:
1.获取当前时间对应的毫秒值
2.获取自己出生日期对应的毫秒值
3.两个时间相减(当前时间– 出生日期)
伪代码流程:
1.使用Scanner类中的方法next,获取出生日期
2.使用DateFormat类中的方法parse,把字符串的出生日期,解析为Date格式的出生日期
3.把Date格式的出生日期转换为毫秒值
4.获取当前的日期,转换为毫秒值
5.使用当前日期的毫秒值-出生日期的毫秒值
6.把毫秒差值转换为天(s/1000/60/60/24)
代码实现:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws ParseException {
// 1.使用Scanner类中的方法next,获取出生日期
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的出生日期,格式:yyyy-MM-dd");
String birthdayDateString = sc.next();
// 2.将出生日期转换为Data格式(调用parse方法)
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date birthdaydata = df.parse(birthdayDateString);
// 3.把Data格式转换为毫秒值
long birthdaydataTime = birthdaydata.getTime();
System.out.println(birthdaydataTime); //973785600000
// 4.获取当前时间并转换为毫秒值
Date data = new Date();
long NowTime = data.getTime();
// 5.相减,将毫秒值转换为天
long time = NowTime - birthdaydataTime;
System.out.println(time/1000/60/60/24); //7226
}
}
2.4Calendar类
1.概念
java.util.Calendar
是日历类,在Date后出现,替换掉了许多Date的方法。
2. 获取方式
Calendar为抽象类,Calendar类在创建对象时并非直接创建,而是通过静态方法创建,返回子类对象,如下:
Calendar静态方法:
-
public static Calendar getInstance()
:使用默认时区和语言环境获得一个日历
例如:
public class Demo01Calendar {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();//多态写法,左边为父类引用,右边new一个子类对象
System.out.println(c);
}
}
3.常用方法
根据Calendar类的API文档,常用方法有:
-
public int get(int field)
:返回给定日历字段的值。 -
public void set(int field, int value)
:将给定的日历字段设置为给定值。 -
public abstract void add(int field, int amount)
:根据日历的规则,为给定的日历字段添加或减去指定的时间量。 -
public Date getTime()
:返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。
成员方法的参数:
int field:日历类的字段,可以使用Calendar类的静态变量获取。
Calendar类中提供很多成员常量,代表给定的日历字段:
字段值 | 含义 |
---|---|
YEAR | 年 |
MONTH | 月(从0开始,可以+1使用) |
DAY_OF_MONTH | 月中的天(几号) |
HOUR | 时(12小时制) |
HOUR_OF_DAY | 时(24小时制) |
MINUTE | 分 |
SECOND | 秒 |
DAY_OF_WEEK | 周中的天(周几,周日为1,可以-1使用) |
get/set方法
- get方法用来获取指定字段的值。get方法默认获取当前时间。
- set方法用来设置指定字段的值。
代码使用演示:
public class Demo02Calendar {
public static void main(String[] args) {
demo01();
demo02();
}
/*
public int get(int field):返回给定日历字段的值。
参数:传递指定的日历字段(YEAR,MONTH...)
返回值:日历字段代表的具体的值
*/
private static void demo01() {
//使用getInstance方法获取Calendar对象
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
System.out.println(year); //2020
int month = c.get(Calendar.MONTH);
System.out.println(month+1);//西方的月份0-11 东方:1-12 //8
//int date = c.get(Calendar.DAY_OF_MONTH);
int date = c.get(Calendar.DATE);
System.out.println(date); //23
}
/*
public void set(int field, int value):将给定的日历字段设置为给定值。
参数:
int field:传递指定的日历字段(YEAR,MONTH...)
int value:给指定字段设置的值
*/
private static void demo02() {
//使用getInstance方法获取Calendar对象
Calendar c = Calendar.getInstance();
// 1.一个一个设置
//设置年为9999
c.set(Calendar.YEAR,9999);
//设置月为9月
c.set(Calendar.MONTH,9);
//设置日9日
c.set(Calendar.DATE,9);
//2. 同时设置年月日,可以使用set的重载方法
c.set(8888,8,8);
int year = c.get(Calendar.YEAR);
System.out.println(year); //8888
int month = c.get(Calendar.MONTH);
System.out.println(month);//西方的月份0-11 东方:1-12 //8
int date = c.get(Calendar.DATE);
System.out.println(date); //8
}
}
add方法
add方法可以对指定日历字段的值进行加减操作,如果第二个参数为正数则加上偏移量,如果为负数则减去偏移量。
代码如:
public class Demo02Calendar {
public static void main(String[] args) {
demo03();
}
/*
public abstract void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
把指定的字段增加/减少指定的值
参数:
int field:传递指定的日历字段(YEAR,MONTH...)
int amount:增加/减少指定的值
正数:增加
负数:减少
*/
private static void demo03() {
//使用getInstance方法获取Calendar对象
Calendar c = Calendar.getInstance();
//把年增加2年
c.add(Calendar.YEAR,2);
//把月份减少3个月
c.add(Calendar.MONTH,-3);
int year = c.get(Calendar.YEAR);
System.out.println(year); // 2022
int month = c.get(Calendar.MONTH);
System.out.println(month);//西方的月份0-11 东方:1-12 //4
//int date = c.get(Calendar.DAY_OF_MONTH);
int date = c.get(Calendar.DATE);
System.out.println(date); //24
}
}
getTime方法
在Date中得getTime()是将Date类型的日期转化为Long类型的毫秒值,但是在
Calendar中的getTime方法并不是获取毫秒时刻,该类重写了getTime(),作用是拿到对应的Date类型对象。
public class Demo02Calendar {
public static void main(String[] args) {
demo04();
}
/*
public Date getTime():返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。
把日历对象,转换为日期对象
*/
private static void demo04() {
//使用getInstance方法获取Calendar对象
Calendar c = Calendar.getInstance();
Date date = c.getTime();
System.out.println(date); //Mon Aug 24 23:37:58 CST 2020
}
}
2.5 日期相关类总结
1.Date类
A. 构造方法
- 无参构造:Date(),根据系统时间创建日期对象
- 有参构造:Date(long time),根据传入的毫秒值创建时间对象(1970-01-01-00:00【中国推迟8个小时】)
B. 成员方法
- long getTime(),获取当前Date日期对象的毫秒值时间
- String toLocaleString(),根据本地格式显示当前Date对象。
2.DataFormat类&SimpleDateFormat类
A. 构造方法
- SimpleDateFormat(String s),根据指定模板创建日期格式化对象
B. 成员方法
- String format(Date d),根据指定格式将d转化为字符串。
- Date parse(String s),根据指定格式传入字符串,返回Date对象
3. Calendar类
A. 创建Calendar类对象方式
- Calendar c = Calendar.getInstance(),获取日历对象
B. 成员方法
- int get(int field),获取当前日历对象的指定日历字段field的信息。
- void set(int field,int val),将指定日历字段field设置为指定的值val
- void add(int field,int val),将指定日历字段field增加/减少指定的值,由val的正负决定。
- Date getTime(),将当前日历对象转化为Date对象。
对于前三个方法的参数field,类似于每一个字段的索引,其在Calendar类中都是静态的变量,并使用final修饰,也就是说不可改变的:
public static final int ERA = 0; public static final int YEAR = 1; public static final int MONTH = 2; public static final int WEEK_OF_YEAR = 3; public static final int WEEK_OF_MONTH = 4; ...
所以我们传入的参数其实是得到每个字段的索引值,get()获取的是该索引对应的值,set设置该索引对应值的值。...
网友评论