抽象类和接口(三)

发布于:2022-12-19 ⋅ 阅读:(153) ⋅ 点赞:(0)

Object:超类

Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父
类。即所有类的对象都可以使用Object的引用进行接收。

package One;


import java.util.Objects;

public class Date {         //Date没有继承任何类但是使用关键字super调用Object,Object:超类,当一个类没有继承自任何类则默认继承Object
                            //Objecct没有基类
    int year;
    int month;
    int day;

    public Date(int year, int month, int day) {
        super();//在构造方法中super关键字调用基类的构造方法
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public String toString() {
        /*System.out.println(getClass().getName());
        System.out.println(hashCode());
        return super.toString();
         */
        return "["+year+"-"+month+"-"+day+"]";
    }
   public static void method1(){
       Date d1=new Date(1222,3,3);
       System.out.println(d1);
   }
   public static void method2(){
        int a=10;
        int b=20;
        int c=10;
        //内置类型使用”=="比较
        //"=="左右两端如果是内置类型的变量,直接用变量中的值进行比较
       System.out.println(a==b);
       System.out.println(a==c);
       System.out.println("==========");
       //自定义类型使用"=="比较
       //d1和d3日期相同应该返回true,d2和d1不同应该返回false
       //但是最终都返回了false,并不是将引用对象的内容进行比较
       //而是将引用对象的地址进行比较
       Date d1=new Date(1111,1,1);
       Date d2=new Date(1222,2,2);
       Date d3=new Date(1111,1,1);
       System.out.println(d1==d2);
       System.out.println(d1==d3);
       //注意:如果想要比较内容,则需要调用equals方法来进行比较,但是一定要对Object中的equals方法进行重写
       System.out.println("==============");
       System.out.println(d1.equals(d2));
       System.out.println(d1.equals(d3));
       System.out.println(d1.equals(null));
   }

    @Override
    public boolean equals(Object obj) { //重写equals方法不能对其中变量进行修改
        //1、检查是否为空,如果为空则返回false
        if(obj==null){
            return false;
        }
        //2、this==obj:检测是否指向同一个对象,既然对象一样,则内容肯定一样,就没有必要去逐个比较了
        if(this==obj){
            return true;
        }
        //3、当两个不同的对象进行比较时:此时应该检测obj是否是当前一个类的对象,如果不是该类的对象则肯定不相等,返回false
        if(!(obj instanceof Date)){
            return false;
        }
        //4、说明:obj现在就是Date的一个对象,将obj强转为当前类的对象,然后使用对象中的成员逐个进行比较
        Date d=(Date)obj;
        return(year==d.year)&&
                (month==d.month)&&
                (day==d.day);
    }
    public static void method3(){
        //两个对象内容相同,一般情况下,我们会让其哈希码也相同,但实际上不一样
        Date d1=new Date(1111,1,1);
        Date d3=new Date(1111,1,1);
        System.out.println(d1.hashCode());
        System.out.println(d3.hashCode());
        //两个对象内容相同,要想让其哈希码相同,则我们就要对其Object中的hashCode()方法进行重写:用对象中的成员去计算hashCode
    }

    @Override
    public int hashCode() {
        return Objects.hash(year,month,day);
    }

    public static void main(String[] args) {
      // method1();
      // method2();
        method3();
    }
}

Clonable 接口和深拷贝
Java 中内置了一些很有用的接口, Clonable 就是其中之一.
Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要
先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.

package Two;


public class Date implements Cloneable{         //Date没有继承任何类但是使用关键字super调用Object,Object:超类,当一个类没有继承自任何类则默认继承Object
                            //Objecct没有基类
    int year;
    int month;
    int day;
    Time t;
    public Date(int year, int month, int day,Time t) {
        super();//在构造方法中super关键字调用基类的构造方法
        this.year = year;
        this.month = month;
        this.day = day;
        this.t=t;
    }

    @Override
    public String toString() {
        /*System.out.println(getClass().getName());
        System.out.println(hashCode());
        return super.toString();
         */
        return "["+year+"-"+month+"-"+day+"]";
    }


    @Override
    public boolean equals(Object obj) { //重写equals方法不能对其中变量进行修改
        //1、检查是否为空,如果为空则返回false
        if(obj==null){
            return false;
        }
        //2、this==obj:检测是否指向同一个对象,既然对象一样,则内容肯定一样,就没有必要去逐个比较了
        if(this==obj){
            return true;
        }
        //3、当两个不同的对象进行比较时:此时应该检测obj是否是当前一个类的对象,如果不是该类的对象则肯定不相等,返回false
        if(!(obj instanceof Date)){
            return false;
        }
        //4、说明:obj现在就是Date的一个对象,将obj强转为当前类的对象,然后使用对象中的成员逐个进行比较
        //内部包含类中也必需要重写equal方法
        Date d=(Date)obj;
        return(year==d.year)&&
                (month==d.month)&&
                (day==d.day)&&
                (t.equals(d.t));
    }
     public static void method1(){
         Two.Date d1=new Two.Date(1111,1,1,new Time(11,1,1));
         Two.Date d3=new Two.Date(1111,1,1,new Time(11,1,1));
         System.out.println(d1.equals(d3));
     }
     public static void method2(){
         Two.Date d1=new Two.Date(1111,1,1,new Time(11,1,1));
         Date d2=d1;
         //浅拷贝:这种拷贝只是将对象的地址拷贝一份:即d1和d2指向同一个对象,引用对象时就会引用同一个对象,不可取
         d1.day=4;
         System.out.println(d1);
         System.out.println(d2);
         d2.day=5;
         System.out.println(d1);
         System.out.println(d2);
         //这种方法并不是去拷贝对象只是多一个引用去共享对象
    }
    //对象的拷贝
    public static void method3() throws CloneNotSupportedException {
        Two.Date d1=new Two.Date(1111,1,1,new Time(11,1,1));
        //将对象拷贝一份
        Date d2=(Date)d1.clone();
        System.out.println(d2);
        //clone方法会抛出异常,简单处理异常:Alt+enter
        //注意:一个类要想实现克隆方法必须要实现Cloneable接口
        //表明:该类支持克隆,否则就会抛出异常
    }

    @Override
    protected Date clone() throws CloneNotSupportedException {
        Time newTime=new Time(t.hour,t.minute,t.second);
       return new Date(year,month,day,new Time(2,3,4));
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        // method1();
       // method2();
        method3();

    }
}
package Two;

public class Time implements Cloneable{
    public int hour;
    public  int minute;
    public  int second;

    public Time(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

    @Override
    public String toString() {
        return "["+hour+"-"+minute+"-"+second+"]";
    }
    public static void method(){
        Time t1=new Time(11,11,11);
        Time t2=new Time(11,11,11);
    }

    @Override
    public boolean equals(Object obj) {
       if(obj==null){
           return false;
       }
       if(this==obj){
           return true;
       }
       if(!(obj instanceof Time)){
           return false;
       }
       Time t1=(Time)obj;
       return (hour==t1.hour)&&
               (minute==t1.minute)&&
               (second==t1.second);
    }


    public static void main(String[] args) throws CloneNotSupportedException {
        Time t1=new Time(12,3,4);
        Time t2=(Time)t1.clone();
        System.out.println(t1);
        System.out.println(t2);
        t1.hour=5;
        t2.minute=3;
        System.out.println(t1);
        System.out.println(t2);
        //此时为深拷贝t1和t2的地址不同
        //如果克隆对象都是内置成员类型的,此时不需要重写Clonable接口中的抽象方法
        //该类可以直接使用Object中的Clone方法
    }
}

再来重写创建一个Three包调用Two中的Time类

package Three;


import Two.Time;

public class Date implements Cloneable{         //Date没有继承任何类但是使用关键字super调用Object,Object:超类,当一个类没有继承自任何类则默认继承Object
                            //Objecct没有基类
    int year;
    int month;
    int day;
    Time t;
    public Date(int year, int month, int day, Time t) {
        this.year = year;
        this.month = month;
        this.day = day;
        this.t=t;
    }

    @Override
    public String toString() {
        return "["+year+"-"+month+"-"+day+"-"+"]"+t;
    }
//如果此时类中包含引用类型的成员变量,此时没有重写Object类中的Clone方法,但是继续使用clone接口
//如果此时包含引用类型的成员变量,拷贝结束之后,新对象和原对象中引用的成员变量都指向同一个实体
//一个实体将变量修改之后,另外一个实体也会改变,为了解决这个问题,可以利用深拷贝的方式来解决:
    //1、可以重写Object类中Clone方法
    //2、在重写clonef方法中,直接new新对象,将原对象中的每个成员放到新对象中
    //注意如果新对象中也有引用类型变量,引用类型的对象也要重新创建一个
    public static void method1() throws CloneNotSupportedException {
        //深拷贝:Date重写Object中的clone方法
        Date d=new Date(2,3,1,new Time(2,3,4));
        Date d1=(Date)d.clone();
        System.out.println(d);
        System.out.println(d1);
        d.t=new Time(1,3,4);
        System.out.println(d);
        System.out.println(d1);
    }
//对object中的Clone类进行重写:返回值改为Date类,访问权限改为public,创建引用类型的一个新对象,返回Date
    @Override
    public Date clone() throws CloneNotSupportedException {
       Time newTime=new Time(t.hour,t.minute,t.second);
       return new Date(year,month,day,newTime);
    }

    /*public static void method2() throws CloneNotSupportedException {
       //浅拷贝:Date类中没有重写Object中的Clone方法
        Date d=new Date(2,3,1,new Time(2,3,4));
        Date d1=(Date)d.clone();
        System.out.println(d);
        System.out.println(d1);
        d.t=new Time(1,3,4);
        System.out.println(d);
        System.out.println(d1);
    }
     */
    public static void main(String[] args) throws CloneNotSupportedException {
      method1();
      //method2();
    }
}

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别.
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中
不能包含普通方法, 子类必须重写所有的抽象方法.
如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此
处的 Animal 只能作为一个抽象类, 而不应该成为一个接口


网站公告

今日签到

点亮在社区的每一天
去签到