2020-08-18--Java--day01【Object类、

2020-08-18  本文已影响0人  program_white

主要内容

1.Object类

1.1概述

java.lang.Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。

如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:

public class MyClass /*extends Object*/ {
    // ...
}

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。今天我们主要学习其中的2个:

1.2 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方法
    }
}

1.3 equals方法

1.Object类中的Equals()

Person类默认继承了Object类,所以可以使用Object类的equals方法.

public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

equals方法源码:

public boolean equals(Object obj) {
         return (this == obj);
}           

举例:
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。

所以我们在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);

    }
}

1.5Object类方法总结

1.toString()方法
  1. 作用:打印对象信息
  2. 重写前:打印的是包名类名@地址值
  3. 重写后;打印的是对象自定义的内容
2.equals()方法
  1. 作用:比较两个对象
  2. 重写前:比价两个对象的地址值(Object类)
  3. 重写后:比较类中自定义的内容
3.Objec类中静态equals()
  1. 作用:比较两个对象是否相同。
    只是加了一些健壮性操作,防止空指针异常。

2.日期时间类

注意:
中国属于东八区,会把时间增加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对象之间进行来回转换。

1.构造方法

由于DateFormat为抽象类,不能直接使用,所以需要创建常用的子类java.text.SimpleDateFormat的对象来使用。
这个类的构造方法需要一个模式(格式)来指定格式化或解析的标准。构造方法为:

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 class Demo01Calendar {
    public static void main(String[] args) {
        Calendar c = Calendar.getInstance();//多态写法,左边为父类引用,右边new一个子类对象
        System.out.println(c);
    }
}
3.常用方法

根据Calendar类的API文档,常用方法有:

成员方法的参数:
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方法

代码使用演示:

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. 构造方法

B. 成员方法

2.DataFormat类&SimpleDateFormat类

A. 构造方法

B. 成员方法

3. Calendar类

A. 创建Calendar类对象方式

B. 成员方法

对于前三个方法的参数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设置该索引对应值的值。...

上一篇下一篇

猜你喜欢

热点阅读