CS-Notes打卡第四天Object、继承

CS-Notes地址

Object

正如Object的javaDoc描述,Object类是一切类的父类
Class {@code Object} is the root of the class hierarchy.
Every class has {@code Object} as a superclass. All objects,
including arrays, implement the methods of this class.

方法概览

1.public native int hashCode()
2.public boolean equals(Object obj)
3.protected native Object clone() throws CloneNotSupportedException
4.public String toString()
5.public final native Class<?> getClass()
6.protected void finalize() throws Throwable {}
7.public final native void notify()
8.public final native void notifyAll()
9.public final native void wait(long timeout) throws InterruptedException
10.public final void wait(long timeout, int nanos) throws InterruptedException
11.public final void wait() throws InterruptedException
因为Object类是所有类的父类,因此所有类都具备上述的方法。
在这里插入图片描述

equals()

equals是逻辑上进行比较,并不是真正物理上进行比较。

等价关系

equals上面进行逻辑相等需要满足五种情况:
1.自反性即 x.equals(x) =>true
2.对称性即 x.equals(y) == y.equals(x) =>ture或者false
3.传递性即 x.equals(y) == true 且 y.equals(z) == true因此存在x.equals(z) == true
4.一致性,即多次对比结果一致
5.与null对比,任何不是null的对象与null进行equals对比都是false

与==的区别

==一般用于基本类型的对比,在对象上面使用是判断两个对象是否引用同一个对象。基本类型没有equals方法,同时在对象上一般用equals判断两个对象的引用的值是否一致。
例如字符串的判断

//为啥不用String s1 = "abc",因为这个涉及到StingPool会导致后面的对象跟前面对象引用一致,因此我们还是用new 来做对比
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // true
System.out.println(s1== s2);      // false

实现
当我们需要使用equals的时候需要在类中重写equals的实现例如String中的equals的重写:当需要对比的对象是String且是同样的编码实现,当byte数组长度一致时,一个个比较值

 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (!COMPACT_STRINGS || this.coder == aString.coder) {
                return StringLatin1.equals(value, aString.value);
            }
        }
        return false;
    }
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

hashCode()

hashCode是返回hash值的方法,当两个对象等价,其hash值一定等值,但是两个对象的hash值相等,不一定等价。在重写equals方法时,最好重写hashCode方法确保等价的两个对象的hash值也相等。

因为HashSet和HashMap保存的时候,是通过计算key的hashCode来保存。当我们使用HashSet和HashMap保存对象时,假如不重写hashCode方法,可能导致两个等价的对象因为计算出来的hashCode不一致认为是不一样的从而保存重复数据。例如:

		Pojo p = new Pojo(1);
        Pojo q = new Pojo(1);
        System.out.println(p.hashCode());
        System.out.println(q.hashCode());
        Set set = new HashSet();
        set.add(p);
        set.add(q);
        System.out.println(set.size());

在这里插入图片描述
不重写hashCode方法,导致两个等价的对象重复保存。

toString()

toString方法当我们不重写的时候一般是
类路径@散列码无符号16进制表示,例如

com.my.method.ObjectTest@4edde6e5

clone()

clone方法在Object类中修饰符为protect的,如果一个类不显示的重写clone方法,其他类也无法直接调用该类实例的clone方法

CloneNotSupportedException
当我们重写clone方法的时候,直接super调用父类的方法,会看到需要我们声明一个异常CloneNotSupportedException,声明完然后调用。喜闻乐见报错:
Exception in thread “main” java.lang.CloneNotSupportedException: com.my.method.ObjectTest$Pojo

	static class Pojo{
        int a;
        static int b;
        Pojo(int a){
            this.a = a;
        }

        @Override
        public Pojo clone() throws CloneNotSupportedException {
            return (Pojo) super.clone();
        }
    }
	public static void main(String[] args) throws CloneNotSupportedException {
        Pojo p = new Pojo(1);
        Pojo q = new Pojo(1);
        Pojo c = p.clone();
    }

然后点进去CloneNotSupportedException异常类会看到这段JavaDoc
Thrown to indicate that the clone method in class
Object has been called to clone an object, but that
the object’s class does not implement the Cloneable
interface.
当我们声明的接口没有实现Cloneable接口的时候使用clone方法时候抛出

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

浅拷贝

浅拷贝,就是虽然返回了一个新的对象但是两个对象都是指向同一个引用。
例如:

static class Jojo implements Cloneable{
        int[] arr;
        public Jojo(int size , int key){
            arr = new int[size];
            arr[0] = key;
        }

        @Override
        public Jojo clone() throws CloneNotSupportedException {
            return (Jojo) super.clone();
        }
    }
public static void main(String[] args) throws CloneNotSupportedException {
        Jojo jojo = new Jojo(2,1);
        System.out.println("克隆前的值:"+jojo.arr[0]);
        Jojo jojo1 = jojo.clone();
        System.out.println((jojo == jojo1));
        jojo1.arr[0] = 3;
        System.out.println("克隆后的值:"+jojo.arr[0]);
    }

最后的结果:
在这里插入图片描述
虽然两个对象物理上面值不等,但是实际上修改了后面对象的值,前面对象的值也被修改了。

深拷贝

深拷贝就是原对象与克隆对象的引用也不一样

static class JojoForDeepCopy implements Cloneable{
        int[] arr;
        public JojoForDeepCopy(int size , int key){
            arr = new int[size];
            arr[0] = key;
        }

        @Override
        public JojoForDeepCopy clone() throws CloneNotSupportedException {
            JojoForDeepCopy jojoForDeepCopy = (JojoForDeepCopy) super.clone();
            jojoForDeepCopy.arr = new int[arr.length];
            for (int i = 0 ;i < arr.length ;i++){
                jojoForDeepCopy.arr[i] = arr[i];
            }
            return jojoForDeepCopy;
        }
    }
public static void main(String[] args) throws CloneNotSupportedException {
        JojoForDeepCopy jojoForDeepCopy = new JojoForDeepCopy(2,1);
        System.out.println("克隆前的值:"+jojoForDeepCopy.arr[0]);
        JojoForDeepCopy jojoForDeepCopy1 = jojoForDeepCopy.clone();
        jojo1.arr[0] = 3;
        System.out.println("克隆后的值:"+jojoForDeepCopy.arr[0]);
    }

在这里插入图片描述

copy()方法的替换

copy方法不仅需要抛出异常,而且在使用的时候还需要强制进行类型转换,我们可以使用拷贝构造函数或者拷贝工厂进行对象的拷贝。
拷贝构造函数如下:

	static class JojoForDeepCopy{
        int[] arr;
        public JojoForDeepCopy(int size , int key){
            arr = new int[size];
            arr[0] = key;
        }

        public JojoForDeepCopy(JojoForDeepCopy origin){
            this.arr = new int[origin.arr.length];
            for (int i = 0 ;i< origin.arr.length;i++){
                this.arr[i] = origin.arr[i];
            }
        }
    }

继承

访问权限

访问权限本身同一包子类其他包
private×××
无修饰符(friendly)××
protected×
public

访问权限由小到大排列
子类继承父类的时候,访问权限必须大于等于父类确保满足里氏替换原则

抽象类与接口

抽象类
1.抽象类和抽象方法都由abstract声明
2.如果一个类有抽象方法,那么这个类必须声明为抽象类
3.抽象类不能被实例化,只能够被继承
4.抽象类也可以有实现的方法

接口
在Jdk1.8之前接口被认为是抽象的抽象类,不能够实现任何的方法,在jdk1.8之后接口可以添加default方法,这样是为了避免当接口新增一个方法的时候,需要去所有实现类中添加方法。

  1. 接口的成员(字段+方法)默认为public,且不能声明为private和protected
  2. 接口的字段默认都是 static 和 final 的

比较
1.对于抽象类,子类必须覆盖掉父类,而接口只是提供一种方法实现契约,并不需要实现类去覆盖
2.一个类能实现多个接口,而不能继承多个类
3.接口的字段只能是static和final类型,而抽象类不限制
4.接口的成员访问只能是public的,而抽象类有多种访问权限

super

  1. 访问父类构造函数,可以通过super()方法调用父类的构造函数。子类一定会调用到父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果要调用父类的其他构造函数,可以使用super()方法
  2. 访问父类的成员:如果子类重写了父类的某种方法,可以通过super关键字调用父类的方法实现

重写与重载

重写指子类实现了一个与父类声明完全一样的方法
为了满足里氏转换原则,重写需要满足以下三个条件:

  1. 子类中的方法的访问权限必须大于等于父类
  2. 子类中方法的返回类型必须是父类的返回类型,或者是父类的返回类型的子类(这个之前没注意过)
  3. 子类中方法声明的异常必须是父类方法声明的异常,或者是父类方法声明的异常的子类
    在调用一个方法时,先从本类中查找看是否有对应的方法,如果没有再到父类中查看,看是否从父类继承来。否则就要对参数进行转型,转成父类之后看是否有对应的方法。

重载是指同一个类中存在相同的方法名,但是其参数列表,类型,个数,顺序必须有一个不一致,特别注意出参不同,参数列表相同不认为是重载
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Object.xmind
继承.xmind

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值