End

Java 面向对象 继承 多态 重写 覆盖

本文地址


目录

Java 面向对象 继承 多态 重写 覆盖

基础概念

JAVA 面向对象的三大特征

  • 封装 encapsulation
  • 继承 inheritance
    • 继承的缺点:增加了代码间的耦合度,使用不灵活
    • 使用原则:对类的功能的扩展,要多用组合,少用继承
  • 多态 polymorphism

final 关键字

  • final 可以修饰类,方法,变量
  • final 修饰的不可以被继承
  • final 修饰的方法不可以被覆盖
  • final 修饰的变量是一个常量,只能被赋值一次

对象的实例化过程

  • JVM 读取指定的路径下的.class文件,并加载进内存,并会先加载其父类
  • 在堆内存中开辟空间,并分配地址
  • 并在对象空间中,给对象的属性进行【默认初始化】
  • 调用对应的构造函数进行初始化
  • 在构造函数中,第一行会先调用父类的构造函数进行初始化
  • 父类初始化完毕后,再对子类的属性进行【显示初始化】
  • 再进行子类构造函数的特定初始化
  • 初始化完毕后,将地址值赋值给引用变量

构造方法

  • 构造函数的函数名与类名相同,没有返回值类型
  • 若在构造函数前面加上返回值类型,就是一个普通的函数了。允许一个普通函数和构造函数同名同参数列表
  • 多个构造函数是以重载的形式存在的
  • private 修饰的构造函数不被子类继承
  • 若没有显示定义构造函数,则存在默认的无参构造函数
  • 若已显示定义构造函数,则不再有默认的无参构造函数,除非显示定义了无参构造函数
  • 父类构造函数中调用的函数遵循多态原则
  • 即:父类构造函数中调用的【非静态方法】实际执行的是子类中重写的方法

this 和 super

  • this 代表当前对象的引用,就是【函数所属对象】的引用
  • 简单说,哪个对象调用了 this 所在的函数,this 就代表哪个对象
  • 当成员变量和局部变量重名时,可以用 this 来区分
  • this 也可以用于在构造函数中用于调用其他构造函数,但只能定义在构造函数的第一行,因为初始化动作要先执行

  • 子类构造函数的第一条语句,默认会首先访问父类中空参的构造函数
  • 也就是说,子类构造函数的第一行默认为super()语句
  • 如果子类构造函数中第一行使用super(参数)语句调用了父类其他的构造函数,那么默认的super()语句就没有了
  • 如果子类构造函数中第一行使用this()语句调用了其他的构造函数,同样默认的super()语句也没有了
  • 若父类没有空参的构造函数,或者为私有,则子类构造函数的第一行必须显示的通过superthis语句访问其他构造函数
  • 总之,子类对象在进行初始化前,肯定都会先访问父类的构造函数对要初始化的子类对象进行初始化
  • 因为superthis都要求放在第一行,所以两者必须有且只能有一个

多态

Fu fu = new Zi();
  • 子类继承了其父类中所有非私有的成员变量和成员方法
  • 子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量会被隐藏
  • 非静态方法才具有多态的特性,即运行时的调用的是子类的方法
  • 对于静态方法或成员变量,不具有多态的特性,即运行时调用的都是父类的成员
  • 对于强制类型转换后的对象,如 ZI z =(ZI) f,则 z.成员 访问的全部是子类的成员,这和多态没关系

  • 不允许一个类中存在函数名、参数列表完全相同,但返回值不同的两个函数
  • 同样道理,不允许子类中存在和父类函数名、参数列表相同,但返回值不同的函数
  • 同样道理,也不允许子类中存在和父类函数名、参数列表相同,但一个为静态一个为非静态的函数
  • 允许子类从父类中继承的方法的作用域大于父类,但不允许小于父类

  • 一定要注意,成员变量(包括静态的和非静态的)没有多态的概念
  • 父类中有的成员变量,子类既可以继承后直接拿来用,也可以重新定义一个
  • 重写定义一个新的成员变量后,就和父类原有的成员变量没关系了
  • 同样的道理,父类的静态成员变量final 类型的变量在子类中均可以重新定义成一个新的变量

示例代码 - 多态

继承关系

class Fu {
    public String name = "父类的成员变量";

    public String getName() {
        show();      //【1】这里一定要注意,这里调用的是【子类】的方法,这就是多态
        return name; //【2】这里一定要注意,【任何情况】下,这里引用的都是当前类的name,而不是子类的name
    }

    protected void show() {
        System.out.println("父类的方法");
    }
}

class Zi extends Fu {
    public String name = "子类的成员变量"; // 这是子类自己定义的name,和父类中的name没有一点点关系!

    @Override
    public String getName() {
        System.out.println("------------");
        return super.getName(); // 这是子类默认的实现方式
    }

    @Override
    protected void show() {
        System.out.println("子类的方法");
    }
}

测试代码

Fu fu = new Zi();
System.out.println(fu.name);      // 父类的成员变量
System.out.println(fu.getName()); // 父类的成员变量

Zi zi = (Zi) fu;
System.out.println(zi.name);      // 子类的成员变量
System.out.println(zi.getName()); // 父类的成员变量

执行结果

父类的成员变量
------------
子类的方法
父类的成员变量
子类的成员变量
------------
子类的方法
父类的成员变量

示例代码 - 多态2

继承关系

class Fu {
    public String name = "父类的成员变量";
    public String name2 = "父类的成员变量2";
    public static String name3 = "父类的【静态】成员变量";

    public String getName() {
        return name;
    }

    public String getName2() {
        return name2;
    }
}

class Zi extends Fu {
    public String name;

    public Zi() {
        name = "【子类的成员变量】";
        name2 = "继承的成员变量2"; // 这里的赋值实际上是对【父类】成员的赋值
        name3 = "继承的【静态】成员变量";
    }
}

测试代码

Fu fu = new Zi();
Zi zi = (Zi) fu;
System.out.println(fu.name + " - " + zi.name);             // 父类的成员变量 - 子类的成员变量
System.out.println(fu.getName() + " - " + zi.getName());   // 父类的成员变量 - 父类的成员变量
System.out.println(fu.getName2() + " - " + zi.getName2()); // 继承的成员变量2 - 继承的成员变量2
System.out.println(Fu.name3);                              // 继承的【静态】成员变量

示例代码 - 初始化顺序

继承关系

class Fu {
    Fu() {
        System.out.println("父类的构造方法");
        method();
        staticMethod();
    }

    void method() {
        System.out.println("父类的普通方法");
    }

    static void staticMethod() {
        System.out.println("父类的静态方法");
    }
}

class Zi extends Fu {
    Zi() {
        //super(); // 默认是有这么一行代码的,所以才会先调用父类的构造方法
        System.out.println("子类的构造方法");
    }

    @Override
    void method() {
        System.out.println("子类重写的父类的普通方法");
    }

    static void staticMethod() { // 这里就不能用【@Override】标识,已经说明,这个完全是子类自己定义的方法
        System.out.println("子类的静态方法");
    }
}

测试代码

new Zi();

父类的构造方法
子类重写的父类的普通方法 【多态特性】
父类的静态方法          【非多态】
子类的构造方法

2016-09-12

posted @ 2016-09-12 17:27  白乾涛  阅读(1495)  评论(0编辑  收藏  举报