• java基础---20. 继承性


    1 概述

    2 继承的格式

    • 创建父类
    public class Employee {
        public void method(){
            System.out.println("方法执行了!");
        }
    }
    
    • 创建子类

    Teacher

    public class Teacher extends Employee{
    }
    

    Assistant

    public class Assistant extends Employee {
    }
    
    • 调用
    /*
    在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当作父类看待
    例如:父类是员工,子类是讲师,那么“讲师就是一个员工”。关系is-a.
    
    定义父类的格式:(一个普通的类定义)
    public 父类名称 {
        //...
    }
    定义子类格式:
    public class 子类名称 extends 父类名称 {
        //...
    }
     */
    public class Demo01Extends {
        public static void main(String[] args) {
            //创建一个子类对象
            Teacher teacher = new Teacher();
            //Teacher类当中虽然什么都没写,但是会继承来自父类的method方法
            teacher.method();//方法执行了!
    
            //创建另一个子类助教对象
            Assistant assistant = new Assistant();
            assistant.method();//方法执行了!
        }
    }
    

    3 父类成员变量和子类成员变量重名问题

    • 创建父类
    public class Fu {
        int numFu = 10;
        int num = 100;
        public void methodFu() {
            //这里的num是本类当中的,不会向下找子类的
            System.out.println(num);
        }
    }
    
    • 创建子类
    public class Zi extends Fu{
        int numZi = 20;
        int num = 200;
        public void methodZi() {
            //因为本类当中有num,所以这里的nums是本类当中的。若本类中没有才会往上找
            System.out.println(num);
        }
    }
    
    • 调用
    /*
    在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
    1. 直接:通过子类对象访问成员变量
        规则:等号左边是谁就优先用谁,没有则向上找
    2. 间接:通过成员方法访问成员变量
        规则:方法属于谁(定义在谁中)则优先用谁,没有则向上找
     */
    public class Demo01ExtendsField {
        public static void main(String[] args) {
            Fu fu = new Fu();//创建父类对象
            System.out.println(fu.numFu);//10 只能使用父类的东西,没有任何子类类容
    
            Zi zi = new Zi();
            System.out.println(zi.numFu);//10
            System.out.println(zi.numZi);//20
    
            //1 直接访问重名的成员变量
            //num是重名的成员变量
            //等号左边是谁就优先用谁
            System.out.println(zi.num);//200
            System.out.println(fu.num);//100
    
            //2 间接访问重名的成员变量
            //这个方法是子类的,优先用子类的,没有再向上找
            zi.methodZi();//200
            //这个方法是在父类当中定义的,只不过是子类对象借来使用
            zi.methodFu();//100
        }
    }
    

    4 局部变量和成员变量重名问题

    下面解决三种变量重名问题

    • 父类
    public class Fu {
        //1. 父类成员变量
        int num = 10;
    }
    
    • 子类
    public class Zi extends Fu {
        //2.子类成员变量
        int num = 20;
        public void method() {
            //3. 子类方法的局部变量
            int num = 30;
            System.out.println(num);//30
            System.out.println(this.num);//20 本类的成员变量
            System.out.println(super.num);//10 父类的成员变量
        }
    }
    
    • 调用
    /*
    局部变量:          直接写成员变量名
    本类成员变量:      this.成员变量名
    父类的成员变量:    super.成员变量名
     */
    public class Demo01ExtendsField {
        public static void main(String[] args) {
            Zi zi = new Zi();
            zi.method();
        }
    }
    

    5 父类成员方法和子类成员方法重名问题

    • 父类
    public class Fu {
        public void methodFu(){
            System.out.println("父类方法执行!");
        }
        public void method(){
            System.out.println("父类重名方法执行!");
        }
    }
    
    • 子类
    public class Zi extends Fu {
        public void methodZi(){
            System.out.println("子类方法执行!");
        }
        public void method(){
            System.out.println("子类重名方法执行!");
        }
    }
    
    • 调用
    /*
    在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
        创建的对象是谁,就优先用谁,如果没有则向上找。
    
    注意事项:无论的成员方法还是成员变量,如果没有都是向上找,绝对不会向下找子类的。
     */
    public class Demo01ExtendsMethod {
        public static void main(String[] args) {
            Zi zi = new Zi();
    
            zi.methodFu();//父类方法执行!
            zi.methodZi();//子类方法执行!
    
            //zi是子类对象,所以优先用子类方法
            zi.method();//子类重名方法执行!
        }
    }
    

    6 重写

    • Fu
    public class Fu {
        public Object method(){
                return null;//所有的引用类型都可以用null表示
        }
    }
    
    • Zi
    public class Zi extends Fu {
        @Override
        public String method(){
            return null;
        }
    }
    
    • 调用
    /*
    重写(Override)
            概念:在继承关系当中,方法的名称一样,参数列表也一样。(又叫覆盖、覆写)
            特点:创建的是子类对象则优先用子类方法
            而
            重载(Overload):方法的名称一样,参数列表不一样。
    
    方法覆盖重写的注意事项:
    1. 必须保证父子类之间方法的名称相同,参数列表也相同。
    @Override: 写在方法前面,用来检测是不是有效的正确覆盖重写,若程序不报错就证明是重写
    2. 子类方法的返回值必须小于等于父类方法返回值范围。
    提要:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类
    3. 子类方法的权限必须大于等于父类方法的权限修饰符。
    public > proctected > (default) > private
    备注:(default)不是关键字default,而是什么都不写,留空。
     */
    public class Demo01Override {
    }
    
    

    什么时候需要重写呢


    对于投入使用的类若想更新,可以将该类继承过来,并对其中的某些方法进行重写。

    • 父类
    //本来的老款手机
    public class Phone {
        public void call(){
            System.out.println("打电话");
        }
        public void send(){
            System.out.println("发短信");
        }
        public void show(){
            System.out.println("显示号码");
        }
    }
    
    • 子类
    //定义一个新手机,使用老手机作为父类
    public class NewPhone extends Phone {
        @Override
        public void show() {
            //System.out.println("显示号码");
            //更优写法
            super.show();//把父类的show方法拿过来重复利用
    
            //自己的子类再来添加更多内容
            System.out.println("显示姓名");
            System.out.println("显示头像");
    
        }
    }
    
    • 调用
    public class Demo01Phone {
        public static void main(String[] args) {
            Phone phone = new Phone();
            phone.call();
            phone.send();
            phone.show();
    //        打电话
    //        发短信
    //        显示号码
    
            NewPhone newPhone = new NewPhone();
            newPhone.call();
            newPhone.send();
            newPhone.show();
    //        打电话
    //        发短信
    //        显示号码
    //        显示姓名
    //        显示头像
    
        }
    }
    

    7 继承中构造方法的访问特点

    特点1
    • 父类
    public class Fu {
        public Fu(){
            System.out.println("父类构造方法");
        }
    }
    
    • 子类
    public class Zi extends Fu {
        public Zi(){
            //默认这里有super();用于调用父类无参构造方法
            System.out.println("子类构造方法");
        }
    }
    
    • 调用
    /*
    继承关系中,父子类构造方法访问特点:
    1. 子类构造方法当中有一个默认隐含的super调用,所以一定是先调用父类构造,后执行子类构造
    2. 可以通过super关键字来子类构造调用父类重载构造
     */
    public class Demo01Constructor {
        public static void main(String[] args) {
            Zi zi = new Zi();//先打印父类再打印子类
    //        父类构造方法
    //        子类构造方法
        }
    }
    
    特点2
    • 父类
    public class Fu {
        public Fu(){
            System.out.println("父类构造方法");
        }
        public Fu(int num){
            System.out.println("父类有参构造方法");
        }
    }
    
    • 子类
    public class Zi extends Fu {
        public Zi(){
            //此时不再有super()无参的调用了
            super(10);//只能调用一个super
            System.out.println("子类构造方法");
        }
    }
    
    • 调用
    /*
    继承关系中,父子类构造方法访问特点:
    1. 子类构造方法当中有一个默认隐含的super调用,所以一定是先调用父类构造,后执行子类构造
    2. 子类构造可以通过super关键字来调用父类重载构造
     */
    public class Demo01Constructor {
        public static void main(String[] args) {
            Zi zi = new Zi();//先打印父类再打印子类
    //        父类有参构造方法
    //        子类构造方法
        }
    }
    
    特点3
    • 父类
    public class Fu {
        public Fu(){
            System.out.println("父类构造方法");
        }
        public Fu(int num){
            System.out.println("父类有参构造方法");
        }
    }
    
    
    • 子类
    public class Zi extends Fu {
        public Zi(){
            //super()
            super(10);//只能有一个super()
            System.out.println("子类构造方法");
        }
    
        public void method(){
    //        super();错误写法!只有子类构造方法才能调用父类构造方法。
        }
    }
    
    • 调用
    /*
    继承关系中,父子类构造方法访问特点:
    1. 子类构造方法当中有一个默认隐含的super调用,所以一定是先调用父类构造,后执行子类构造
    2. 子类构造可以通过super关键字来调用父类重载构造
    3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造.
    
    总结: 子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个
     */
    public class Demo01Constructor {
        public static void main(String[] args) {
            Zi zi = new Zi();//先打印父类再打印子类
    //        父类有参构造方法
    //        子类构造方法
        }
    }
    

    8 super关键字小结

    • 父类
    public class Fu {
        int num = 10;
        public void method(){
            System.out.println("父类方法");
        }
    }
    
    • 子类
    /*
    super关键字的用法有三种:
    1. 在子类的成员方法中,访问父类的成员变量
    2. 在子类的成员方法中,访问父类的成员方法
    3. 在子类的构造方法中,访问父类的构造方法
     */
    public class Zi extends Fu {
        int num = 20;
        
        //3.
        public Zi(){
            super();
        }
        public void methodZi(){
            System.out.println(num);
            //1.
            System.out.println(super.num);
        }
        public void method(){
            //2.
            super.method();//访问父类成员方法
            System.out.println("子类方法");
        }
    }
    

    9 this关键字小结

    • 父类
    public class Fu {
        int num = 30;
    }
    
    • 子类
    /*
    super关键字用来访问父类类容,this关键字用来访问子类内容。用法也有三种:
    1. 在本类成员方法中,访问本类成员变量
    2. 在本类的成员方法中,访问本类的另一个成员方法
    3. 在本类的构造方法中访问本类的另一个构造方法
    在第三种方法中要注意:
    this(...)调用也必须是构造方法的第一个语句,唯一一个
    super()和this()两种构造调用不能同时使用,它们必须都是唯一的。
     */
    public class Zi extends Fu {
        int num = 20;//成员变量
    
        //3
        public Zi(){
            //super不会再赠送
            this(123);//本类的无参构造调用本类的有参构造
            //this(123, 456);错误写法,这里必须是第一个语句
        }
        public Zi(int n){
            this(123, 456);
        }
        public Zi(int n, int m) {
            //this();不可以这样,否则就是循环调用了
        }
    
        //1.
        public void showNum(){
            int num = 10;//局部变量
            System.out.println(num);//局部变量
            System.out.println(this.num);//本类中的成员变量
            System.out.println(super.num);//父类中的成员变量
        }
        //2.
        public void methodA(){
            System.out.println("AAA");
        }
        public void methodB(){
            //methodA();或者
            this.methodA();//强调一下该方法来源于本类而不是父类
            System.out.println("BBB");
        }
    }
    

    10 super与this关键字图解

    • 父类
    public class Fu {
        int num = 10;
        public void method(){
            System.out.println("父类方法");
        }
    }
    
    • 子类
    public class Zi extends Fu {
        int num = 20;
        @Override
        public void method(){
            super.method();
            System.out.println("子类方法");
        }
        public void show(){
            int num = 30;
            System.out.println(num);//30
            System.out.println(this.num);//20
            System.out.println(super.num);//10
        }
    }
    
    • 调用
    public class Demo {
        public static void main(String[] args) {
            Zi zi = new Zi();
            zi.show();
            //30
            //20
            //10
            zi.method();
            //父类方法
            //子类方法
        }
    }
    
    • [[super_class]]就是在Zi.class里面做一个标记,告诉其父亲是谁
    • 栈里面子内内容的方法和父内内容的方法存放的都是地址值

    11 继承的三个特点


    注意:爷爷类也称为父类,只不过不是直接父类

  • 相关阅读:
    struct 结构体解析(原)
    C++标准编程:虚函数与内联
    基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现
    直接用编译器按ctrl+F5运行和双击运行结果不一样
    驱动编译的时候注意编译工程选项
    驱动编译的时候注意编译工程选项
    'ddkbuild.cmd' 不是内部或外部命令,也不是可运行的程序
    'ddkbuild.cmd' 不是内部或外部命令,也不是可运行的程序
    NtOpenProcess被HOOK,跳回原函数地址后仍然无法看到进程
    NtOpenProcess被HOOK,跳回原函数地址后仍然无法看到进程
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12235602.html
Copyright © 2020-2023  润新知