• 【JAVA零基础入门系列】Day13 Java类的继承与多态


    继承是类的一个很重要的特性,什么?你连继承都不知道?你是想气死爸爸好继承爸爸的遗产吗?(滑稽)

    开个玩笑,这里的继承跟我们现实生活的中继承还是有很大区别的,一个类可以继承另一个类,继承的内容包括属性跟方法,被继承的类被称为父类或者基类,继承的类称为子类或者导出类,在子类中可以调用父类的方法和变量。在java中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类。但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类。这就相当于一个人不能有多个父亲一样(滑稽,老王表示不服)。

    话不多说,先看栗子:

    public class Employee {
        private String name;//姓名
        private double salary;//薪水
    
        //构造函数
        public Employee(String name,double salary){
            this.name = name;
            this.salary = salary;
        }
      
        public String getName() {
            return name;
        }
    
        public double getSalary() {
            return salary;
        }
    }

    我们定义了一个Employee类(雇员类),并定义了一些简单的成员变量以及方法,接下来定义一个Manager类(经理类)来继承这个类。

    public class Manager extends Employee{
        private double bonus;//奖金
    
      //构造器
        public Manager(String name, double salary){
            super(name,salary);
            bonus = 0;
        }
    
      //设置奖金
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
      //重载父类的getSalary方法
        @Override
        public double getSalary() {
            double baseSalary = super.getSalary();
            return baseSalary + bonus;
        }
    }

    这里需要说明的是super跟this的使用,super是父类引用,可以用它来调用父类的方法和属性,可以把它看作是父类跟子类沟通的桥梁,而this则是自身引用,可以通过它来调用自身的属性和方法,在构造器中我们使用了 super(name,salary); 这样会调用父类的构造函数,

    为什么Manager可以继承Employee这个类呢?是因为它们之间存在is-a的关系,经理也是一个雇员,有很多跟雇员相同的属性如姓名,薪水,以及方法,如取姓名,取薪水,但是它也有自己独有的属性和方法,还可以重载父类的方法,如上面的getSalary。这里的Manager类对象,继承了父类Employee的方法,因此Manager对象可以直接使用getName()方法,重载了getSalary方法,因此调用Manager对象的该方法时,调用的是子类的getSalary方法,而不是父类,

    那到底可以继承父类的哪些信息呢?

    1.子类可以继承父类的成员变量

    当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量。具体的原则如下:

    1)能够继承父类的public和protected成员变量;不能够继承父类的private成员变量;

    2)对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

    3)对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。

    2.子类继承父类的方法

    同样地,子类也并不是完全继承父类的所有方法。

    1)能够继承父类的public和protected成员方法;不能够继承父类的private成员方法;

    2)对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

    3)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。

    这里说了很多次public,private和protected,关于访问权限好像没还有正式介绍,这里来顺便简单介绍一下吧:

    Java类具有三种访问控制符:private、protected和public,同时当不写这三个访问控制符时,表现为一种默认的访问控制状态。因此,一共具有四种访问控制级别。

    具体访问控制表现如下:

    private修饰的属性或方法为该类所特有,在任何其他类中都不能直接访问;

    default修饰的属性或方法具有包访问特性,同一个包中的其他类可以访问;

    protected修饰的属性或方法在同一个中的其他类可以访问,同时对于不在同一个包中的子类中也可以访问;

    public修饰的属性或方法外部类中都可以直接访问。

    为什么要引入访问权限这个概念呢?当然是为了更好的封装,就像制作一台机器一样,自然希望把所有的电线都藏在盒子里而不是大摇大摆的吊在外面被人吐槽,而且这样也更加安全,只给用户或用户程序员看那些想给他们看的内容就好了,其他的一律隐藏起来。

    子类Manager虽然没有继承父类Employee的name和salary属性,但不代表对这两个属性的操作没有意义,可以理解成一个子类对象中包含有一个父类对象,打个比方,就像是我们组装好几款不同的电脑,为了方便起见可以选用同一款主机箱,里面配置了相同的电源和风扇,而其它的配置每台电脑都可以不一样,甚至如果需要的话,某些电脑还可以更换一下风扇和电源,虽然最后性能可能相去甚远,但是从外表上看起来,它们都是差不多的。(当然,如果你非要改装的完全不一样也是可以的)这里的配置好风扇跟电源的主机箱就相当于我们的父类,而不同的电脑就相当于子类,子类可以调用父类的公开方法,如转动风扇,但不能直接改变主机箱的颜色,因为父类并没有提供这样的权限。但这不代表主机箱的颜色对于子类没有用,它仍属于子类的一部分,只是不能直接操作它罢了。

    访问权限的内容就介绍到这里了,现在回归到我们的继承上来,下面是使用Manager类的一个栗子:

    public class ManagerTest {
        public static void main(String[] args){
            Manager boss  = new Manager("Frank",100000);//定义一个Manager变量
            boss.setBonus(10000);//设置奖金
    
            Employee[] staff = new Employee[3];//创建一个Employee数组
         
         //给数组赋值
            staff[0] = boss;
            staff[1] = new Employee("Alan",8000);
            staff[2] = new Employee("Tom",9000);
         //遍历输出数组元素
            for (Employee e:staff)
                System.out.println("name:"+e.getName()+" salary:"+e.getSalary());
        }
    }

    这里我们定义了一个Employee数组,然后把一个Manager变量赋值给了Employee数组的第一个元素,看到这里,你也许会感到疑惑,不是说只能在相同类型的变量之间使用赋值操作吗?确实如此,但是因为Manager类是Employee的子类,一个Manager对象同时具有Employee的所有属性跟方法,也就是说Employee能做的事情,它也同样能做,所以,把Manager类的变量赋值给Employee变量是没有问题的,但反之则不行,因为Manager类有它自己的方法setBonus(),Employee是无法实现。在遍历输出的时候,我们把所有元素都当成Employee对象来使用,输出如下:

    name:Frank salary:110000.0
    name:Alan salary:8000.0
    name:Tom salary:9000.0

    我们boss变量,在调用getSalary方法的时候,显然是调用了子类的方法,将基本薪水加上了奖金之后才进行返回。

    那说了这么多,为什么非要使用继承呢?

    原因很简单,一个是可以实现代码的复用,像这个例子一样,Employee的getName方法被子类Manager复用了,Manager中可以直接使用这个方法,这样可以省去很多代码。

    其次是可以实现多态,说出来你可能不信,我们刚才的栗子已经使用到了一个很伟大的概念——多态,在遍历输出的时候,一个父类对象的引用指向了子类对象,并调用了子类方法。

    那么这样做的好处是什么呢?多态的意义何在?

    简单,方便,继续用我们刚才的栗子,假如我们现在有一个人事管理类,PersonnelManagement,需要对员工的信息进行录入,有一个record方法,我们如果使用了多态的特性,只需要给record方法传入一个Employee对象即可,不管是经理还是普通雇员都能使用相同的方式进行处理,否则我们需要为经理跟雇员分别设计一个方法,这样也许觉得没事,但如果现在又多了很多其它岗位,如总经理,副经理,经理助手,人事部经理,采购部经理,这时候你还能为每个岗位设计一个方法吗?显然不现实,而且这样就失去了可扩展性跟灵活性,把一门艺术活变成了体力活,这样会让你丧失对编程的乐趣。

    所以,继承跟多态其实也很简单,继承就是使用extends来继承父类的属性跟方法,多态则是可以在合适的时候将子类对象视为父类对象进行统一处理,从而实现和增加代码的复用度,让你的代码越来越风骚。

    至此类的继承与多态就讲解完毕了,欢迎大家继续关注!喜欢我的教程的话记得动动小手点下推荐,也欢迎关注我的博客。

    真正重要的东西,用眼睛是看不见的。

  • 相关阅读:
    [Go] 解决packets.go:36: read tcp 127.0.0.1:51139->127.0.0.1:3306: wsarecv: An established connection was aborted by the software in your host ma chine.
    [javascript] js格式化时间为xx秒前、xx分钟前、xx小时前等
    [日常]UserAgent中的AhrefsBot解释
    [PHP] laravel 框架多项目公用redis会有默认前缀 项目名_database_key
    [Go] go run 时 os.Getwd 和 os.Executable 获取程序根路径
    [laravel] 关闭laravel数据库model维护create_at update_at
    [Go]go.mod 文件中的// indirect意思代表间接依赖
    [Go] 解决 imported from implicitly required module
    [mysql] 解决SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column
    [PHP] windows环境下PHP增加rdkafka扩展 解决需要ext-rdkafka问题
  • 原文地址:https://www.cnblogs.com/banxian-yi/p/10579470.html
Copyright © 2020-2023  润新知