day08

23.继承

23.1 优点:

实现软件重用,避免重复,易于维护,易于理解。

23.2 实现及默认机制

继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。

23.3 具体概念
  • 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
  • 子类继承父类的属性和方法
  • 子类从它的父类中继承可访问的数据域和方法,也可以添加新的数据域和新的方法。

​ “父类”,也称为超类、基类;
​ “子类”,也称为次类、扩展类、派生类。

​ 子类不是父类的子集,子类一般比父类包含**更多的数据域和方法**。父类中的 private 数据域在子类中是不可见的,因此在子类中不能直接使用它们。

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

23.4 所有类都直接或者间接的继承自Object类
方法作用及扩展
equals()默认比较地址,需要重写 见23.4.1
clone()浅拷贝和深拷贝,见24.4.2
hashCode()返回对象的哈希码值,见24.4.3
toString()返回对象的字符串形式,见24.4.4
getClass()它会返回一个你的对象所对应的一个Class的对象,这个返回来的对象保存着你的原对象的类信息,见24.4.5
finalize()24.4.6
23.4.1 关于equals()重写

注意向下转型前的判断,重写后的equals方法大多是对 两个对象成员属性值的判断

public class Animal {
    String color="Animal的color";
    int age;

    public String getColor(){
        return color;
    }
}
public class Dog extends Animal {
    String color ="Dog的color";
    String nickName;


    public String getColor(){
        return color;
    }
    public String getSuperColor(){
        return super.getColor();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Dog)) return false;
        Dog dog = (Dog) o;
        return Objects.equals(color, dog.color) && Objects.equals(nickName, dog.nickName);
    }
  }
23.4.2 关于深浅克隆
  • **浅拷贝:**在填充新对象域的时候,进行简单的字段赋值。

    代码实现

    class Head {
    String s;
    void set(String s1) {
    s = s1;
    }
    }
    public class Person implements Cloneable{

    class Head {
        String s;
        void set(String s1) {
            s = s1;
        }
    }
    public class Person implements Cloneable{
        
        Head head;
        Person(Head head) {
            this.head = head;
        }
        protected Object clone() throws CloneNotSupportedException{
            return super.clone();
        }
        public static void main(String[] args) throws CloneNotSupportedException{
            Person p = new Person(new Head());  
            Person p1 = (Person)p.clone();  
            System.out.println("p == p1 " + (p == p1)); //false
            System.out.println("p.head == p1.head " + (p.head == p1.head)); //true
        }
    
    }
    
    

    }

  • **深拷贝:**按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。(简单来说,就是将该对象内部的对象也克隆一份,而不是简单的引用赋值)

class Head implements Cloneable{
    String s;
    void set(String s1) {
        s = s1;
    }
    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}
public class Person implements Cloneable{
    
    Head head;
    Person(Head head) {
        this.head = head;
    }
    protected Object clone() throws CloneNotSupportedException{
        Person p = (Person)super.clone();
        p.head = (Head)head.clone();
        return p;
    }
    public static void main(String[] args) throws CloneNotSupportedException{
        Person p = new Person(new Head());
        Person p1 = (Person)p.clone();
        System.out.println("p == p1 " + (p == p1)); //false
        System.out.println("p.head == p1.head " + (p.head == p1.head)); //false
    }

}
23.4.3 关于hashCode()

作用是返回对象的哈希码值。是根据对象的地址计算的

补充:

​ (1) HashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,HashCode经常用于确定对象的存储地址;

(2)如果两个对象相同, equals方法一定返回true,并且这两个对象的HashCode一定相同;

(3)两个对象的HashCode相同,并不一定表示两个对象就相同,即equals()不一定为true,只能够说明这两个对象在一个散列存储结构中。

(4)如果对象的equals方法被重写,那么对象的HashCode也尽量重写。

23.4.4 关于toString

直接调用或输出某个对象的引用,默认调用Object类提供的toString( ),返回的相当于是对象地址的16进制表达形式 的字符串类型值

JavaBean的定义规范之一,要求重写toString()

23.4.5 关于getClass()

补充 :

  • 在Java中,万事万物皆对象,每个类都有一个相应的Class对象。通过Class类,可以获得一个类的基本信息,比如属性、方法和构造方法等。

  • getClass()是Object类的方法,该方法的返回值类型是Class类,通过getClass()方法可以得到一个Class类的对象。而.class返回的也是Class类型的对象。所以,如果getClass()和.class返回的内容相等,说明是同一个对象。

  • 既然都可以得到Class的对象,关于getClass()和.class的区别:getClass()方法,有多态能力,运行时可以返回子类的类型信息。.class是没有多态的,是静态解析,编译时可以确定类型信息。

23.4.6 关于finalize()

finalize方法的用途有两个:1.finalize()方法释放本地方法申请的内存;2.作为终结条件

24.Super关键字

24.1 作用

super 表示使用它的类的父类。super 可用于:

  • ​ 调用父类的构造方法;
  • ​ 调用父类的方法(子类覆盖了父类的方法时);
  • ​ 访问父类的数据域(可以这样用但没有必要这样用)。
24.2 注意事项

**super 语句必须是子类构造方法的第一条语句。不能在子类中使用父类构造方法名来调用父类构造方法。 父类的构造方法不被子类继承。调用父类的构造方法的唯一途径是使用 super 关键字,如果子类中没显式调用,则编译器自动将 super(); 作为子类构造方法的第一条语句。这会形成一个构造方法链。

静态方法中不能使用 super 关键字。

如果父类中不含 默认构造函数(就是 类名() ),那么子类中的super()语句就会执行失败,系统就会报错。一般 默认构造函数 编译时会自动添加,但如果类中已经有一个构造函数时,就不会添加。

子类不能直接继承父类中的 private 属性和方法。

​ /由于属性是私有的,所以子类不能直接继承,
​ 需要通过 有参构造 函数进行继承
/

24.3 创建子类对象过程

子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。

在构造一个子类的对象时,父类的构造方法也是会被调用的,而且父类的构造方法在子类的构造方法之前被调用。
在程序运行过程中,子类对象的一部分空间存放的是父类对象。因为子类从父类得到继承,在子类对象初始化过程中可能会使用到父类的成员。
所以父类的空间正是要先被初始化的,然后子类的空间才得到初始化。在这个过程中,如果父类的构造方法需要参数,如何传递参数就很重要了。

注意先后顺序

24.4 关于子类的加载问题

子类的加载顺序为:

  1. 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
  2. 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
  3. 父类非静态代码块( 包括非静态初始化块,非静态属性 )
  4. 父类构造函数
  5. 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
  6. 子类构造函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值