美文网首页
Java继承知识点总结

Java继承知识点总结

作者: cornprincess | 来源:发表于2020-04-20 22:22 被阅读0次

    继承

    利用继承,人们可以基于已存在的类构造一个新类,继承已存在的类就是复用(继承)这些类的方法和域。在此基础上,还可以添加一下新的方法和域,以满足新的需求。

    覆盖方法

    简答的代码示例:

    public class Employee {
        private String name;
        private double salary;
        private LocalDate hireDay;
    
        public Employee(String name, double salary, int year, int month, int day) {
            this.name = name;
            this.salary = salary;
            this.hireDay = LocalDate.of(year, month, day);
        }
    
        public String getName() {
            return name;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public LocalDate getHireDay() {
            return hireDay;
        }
    
        public void raiseSalary(double byPercent) {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + '\'' +
                    ", salary=" + salary +
                    ", hireDay=" + hireDay +
                    '}';
        }
    }
    
    public class Manager extends Employee {
        private double bonus;
    
        public Manager(String name, double salary, int year, int month, int day) {
            // Manager 类的构造器不能访问 Employee 类的私有域,所以必须利用 Employee 类的构造器对这部分私有域进行初始化, 且使用 super 调用构造器的语句必须是子类构造器的第一条语句。
            super(name, salary, year, month, day);
            this.bonus = 0;
        }
    
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
    
        public double geSalary() {
            double baseSalary = super.getSalary();
            return baseSalary + bonus;
        }
    }
    

    上述两个类中,Manager 和 Employee 之间是 “is-a" 的关系” “is-a”是继承的一个明显特征, 根据继承的定义, Manager 类继承了 name, salary, hireDay 三个域以及对应的三个 get 访问器方法。将通用的方法放在超类中,而将具有特殊用途的方法放在子类中,在面向对象程序设计中十分普遍。

    需要注意:

    Manager 类的 getSalary 方法不能直接访问父类的私有域, 只有父类才能访问其私有域,因此需要父类提供一个访问 salary 的公共接口,通过 super 关键字调用。

    super 与 this 的不同:

    super 不是一个对象的引用,不能将 super 付给另一个对象变量,它只是一个指示编译期调用超类方法的特殊关键字。

    父类与子类构造器的关系

    • 当子类没有带参构造器和无参构造器,父类有带参构造器和无参构造器时, 子类会有默认的无参构造器,并且该无参构造器会默认调用父类无参构造器的方法。
    public class ExtendsTest {
        public static void main(String[] args) {
            Son son = new Son(); 
        }
    }
    
    class Father {
        private int age;
    
        public Father() {
            System.out.println("Father no argument constructor");
        }
    
        public Father(int age) {
            this.age = age;
        }
    }
    
    class Son extends Father {
    }
    
    // output
    // Father no argument constructor
    
    • 当子类没有带参构造器和无参构器,父类只有带参构造器时编译时检查会报错,因为当写了带参构造器时系统不会给出默认的无参构造器,此时子类不能调用父类的默认无参构造器。
    class Father {
        private int age;
    
        public Father(int age) {
            this.age = age;
        }
    }
    
    class Son extends Father { // error There is no default constructor available in Father
    }
    
    • 当子类没有带参构造器而有无参构器,且父类同时有带参构造器和无参构造器时,子类的无参构造器在第一行默认调用父类的无参构造器。
    public class ExtendsTest {
        public static void main(String[] args) {
            Son son = new Son();
        }
    }
    
    class Father {
        private int age;
    
        public Father() {
            System.out.println("Father no argument constructor");
        }
    
        public Father(int age) {
            this.age = age;
        }
    }
    
    class Son extends Father {
        private String name;
    
        public Son() {
            System.out.println("Son no argument constructor");
        }
    }
    
    // output
    // Father no argument constructor
    // Son no argument constructor
    

    总结

    • 如果子类的构造器没有显示地调用超类的构造器,则会自动地超类默认(没有参数)的构造器,若父类只存在带惨构造则不会有默认的无参构造器。
    • 如果父类没有无参构造器,并且子类的构造器又没有显示地调用父类的其他构造器,则Java编译期将报告错误。

    final

    如果类用 final 修饰,其他类就不能继承它,如果方法用 final 修饰,子类就不能重写它, 如果类中的域用 final 修饰,这个域在构造对象完成之后就不能被修改。final 修饰符的主要作用为:确保被修饰的对象在子类中不会改变语义。

    注意:

    • final 修饰类时,类中方法自动变成 final, 但不包括域。
    • 如果方法很简单,被频繁调用且没有真正地被覆盖,那么及时编译器会将这个方法进行内联处理(inline),例如内联调用 e.getName() 会被替换为访问 e.name 域。

    强制类型转换

    进行类型转换的唯一原因是:在暂时忽视对象的实际类型之后,使用对象的全部功能。在 Java 中,每个对象变量都属于一个类型,类型描述了这个变量所引用的以及能够引用的对象类型。

    Java 是强类型语言,在将一个值存入变量时,编译器将检查是否允许该操作,将一个子类的引用复制给一个超类变量,编译器时允许的(向上转型,此时会丢失子类扩展的方法),但将一个超类的引用复制给一个子类变量(向下转型,此时可以找回子类扩展的方法),必须进行类型转换,这样才能通过运行时检查。

    一般只有在使用子类中的特有方法是才需要进行强制类型转换,此时可以使用 instanceof 先检查类型,再进行类型转换。

    Employee[] staff = new Employee[3];
    Manager boss = new Manager();
    staff[0] = boss;
    staff[1] = new Employee();
    if (staff[1] instanceof Manager) {
        boss = (Manager) staff[1];
    }
    

    注意:

    null instanceof C // false,不会报错,因为null没有引用任何对象,当然也不会引用C类型对象
    

    本文章与github上同步,欢迎来玩,提交issue。

    Reference

    1.[Java核心技术·卷 I(原书第10版)](继承

    相关文章

      网友评论

          本文标题:Java继承知识点总结

          本文链接:https://www.haomeiwen.com/subject/jjbsihtx.html