java类与类的关系之继承

继承的特点

  • 子类继承父类,通过一个关键字extends实现。
  • 子类的对象可以调用父类中的(public protected)属性和方法,当做自己的来使用。
  • 子类可以添加自己独有的属性和方法
  • 子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法
  • 每一个类都有继承类,如果不写extends关键字继承其他类,则默认继承Object类,如果写了extends关键字则继承那个父类
  • Object类是任何一个引用类型的父类(直接或者间接继承Object类),Object类没有父类
  • java中的继承是单继承,每一个类只能有一个继承类(extends后面只能写一个类),目的是为了让类变得更加安全,例如防止两个类中同时出现一样的属性/方法产生无法抉择问题,因此变得更安全
  • 可以通过传递的方式实现多继承的效果,比如B继承A,C继承B,这样C就有A的成员,通过继承后的类一部分可以被子类覆盖,不会造成无法抉择问题,因此更加安全

Object类中的9个方法

  • getClass():获取对象对应类的类映射
  • hashCode():将对象在内存中的地址经过计算机得到一个int整数,它是native修饰,调用本地C/C++来实现
  • equals(Object obj):用来比较两个对象的内容,Object类中的默认是通过== 比较,即比较的是地址,==比较的是基本类型时比较的是值,比较引用类型时比较的是地址,如果想改变比较的规则,则可重写该方法
  • clone():权限修饰符为protected,用来克隆对象
  • toString():打印输出时对象变成String字符串,默认打印的是类名+@+hashCode二进制转换为Integer值,如果想改变其规则,则可以重写该方法
  • notify():线程唤醒
  • notifyAll():唤醒所有
  • wait()重载方法:线程进入挂起等待状态
  • finalize():权限修饰符是protected,它是在对象被GC回收的时候,默认调用执行的方法,作用是回收对象

深入理解继承在内存中的存储结构

测试示例:
Animal类

public class Animal {
    
    


    public Animal(){
    
    
    	//由于构造方法会有隐藏默认调用父类的构造方法super();因此会调用父类构造方法
        //super();
        System.out.println("这是动物的构造方法");
    }

    public void eat(){
    
    
        System.out.println("这是动物的吃饭方法");
    }
}

Person类

public class Person extends Animal{
    
    


    public Person(){
    
    
        System.out.println("这是人类的构造方法");
    }

    public void eat(){
    
    
        System.out.println("这是人类的吃饭方法");
    }

}

测试类

public class TestMain {
    
    
    public static void main(String[] args) {
    
    
    	//加载类模板的过程
        //Person类  Animal类  Object类
        //创建一个Person类型的对象,调用构造方法,子类、父类
        Person person = new Person();
        //调用eat()方法,从当前类对象开始找方法,如果当前类没有找到该方法,则往父类找该方法,以此类推,如果找到则执行该方法
        person.eat();
    }
}

内存原理图
在这里插入图片描述
执行结果:
在这里插入图片描述
如果注释掉Person类中eat()方法,则再执行该程序结果如下:
在这里插入图片描述

关于this和super在继承中的使用

this和super都是指代词 代替的是对象
this代替的是当前执行方法时的那个对象 不一定是当前类的
super代替的是当前执行方法时的对象的父类对象

测试示例:
Animal类

public class Animal {
    
    
    public Animal(){
    
    
        //super();
        System.out.println("这是动物的构造方法");
    }

    public void eat(){
    
    

        System.out.println("这是动物的吃饭方法");
    }

    public void sleep(){
    
    
    	//此this关键字指代的是调用方法的那个对象,在这里是person对象引用调用,而不是当前Animal类的对象调用,所以他会执行从Person类的eat()方法去找,找到则执行该方法,没找到则去父类寻找该方法
        this.eat();
        System.out.println("这是动物睡觉的方法");
    }
}

Person类:

public class Person extends Animal{
    
    


    public Person(){
    
    
        System.out.println("这是人类的构造方法");
    }

    public void eat(){
    
    
        System.out.println("这是人类的吃饭方法");
    }

}

测试类:

public class TestMain {
    
    
    public static void main(String[] args) {
    
    
        Person person = new Person();
        person.sleep();
    }
}

测试结果:
在这里插入图片描述
如果把Person类中的eat()方法注释掉,则this.eat()方法调用的是当前Animal类中的eat()方法,this指代的是当前调用方法的对象,当前person对象引用先找Person类中的eat()方法,找不到去父类中寻找eat()方法,找到后执行,没找到以此类推。
测试结果:
在这里插入图片描述
this和super

  • 可以放置在类成员的任意位置(属性 方法 构造 块),注意调用一般方法的时候可以来回互相调用(写法 编译好用) 执行可能产生问题(StackOverflowError)
  • 可以调用构造方法(放在构造方法的第一行)
    this和super在构造方法中调用另一个类的构造方法不能同时出现在第一行,构造方法之间不能来回互相调用(编译就不好用)

猜你喜欢

转载自blog.csdn.net/weixin_45608165/article/details/112691718