zoukankan      html  css  js  c++  java
  • Java基础知识点4:继承

      继承是面向对象编程技术中非常重要的一个基本概念。它背后的基本思想就是:通过已有的类来创建一个新的类,这个新的类可以重用(或继承)已有的类方法;新的类也可以加入新的方法和属性。

      在这里我们通过一个实例来讲解继承的基本知识。假设我们在为一个公司设计一个管理系统,管理公司的人员,我们首先定义了一个雇员类Employee,它的定义如下:

    1 public Employee {
     2     private String name;
     3     private double salary;
     4 
     5     public Employee(String name, double salary) {
     6         this.name = name;
     7         this.salary = salary;
     8     }
     9 
    10     public String getName() {
    11         return name;
    12     }
    13 
    14     public void setName(String name) {
    15         this.name = name;
    16     }
    17 
    18     public double getSalary() {
    19         return salary;
    20     }
    21 
    22     public void setSalary(double salary) {
    23         this.salary = salary;
    24     }
    25   
    26 }

    基本语法

    基本定义

      定义一个继承自已有类的子类所涉及到的关键字是extends,基本语法如下:

      子类名  extends  超类名 {

        子类定义的新的属性和方法:

      }

        也就是说,定义一个继承自超类的子类,只需要声明二者不同的地方就可以了。

      比如现在我们想为公司的经理们设计一个类Manager,由于经理也是雇员,所以雇员的基本属性经理也都有。但是经理可能有一些其他雇员没有的属性和方法,比如经理会有分红bonus。所以采用继承的方式来定义Manager类是最合适不过的。

     1 public Manager extends Employee {
     2     
     3     private double bonus;
     4 
     5     public Manager(String name, double salary, double bonus) {
     6         super(name, salary);
     7     this.bonus = bonus;
     8     }
     9 
    10     public double getBonus() {
    11         return bonus;
    12     }   
    13 
    14     public void setBonus(double bonus) {
    15         this.bonus = bonus;    
    16     }
    17 18 }

      这样我们就成功的建立了一个继承自Employee的新类Manager,这个Manager不仅仅具有Employee类的属性和方法,而且还包含自己独有的属性和方法。

      关于子类这里有几点需要注意

      1. 子类能够直接调用超类的public,protected方法。之所以使用protected,这样可以保证这个方法是可以被该超类的子类所应用的。但是不能被其他的类所使用。

      2. 子类不能够访问超类中的private属性,方法。

      3. 子类只能够通过public的接口去访问超类中的private属性。

    覆盖超类方法

      在实际情况中还会出现这样的需求,有些方法在超类中定义了,而且子类也需要使用这个方法。但是,子类对于这个方法的定义与超类的定义不一样。以上面的Manager类为例,Manager需要使用getSalary方法获取它的工资,在超类中的定义就是返回私有域salary的值,但是在Manager中,我们需要返回salary和bonus域的和。这里应该怎么去实现?

      这里就需要Manager类去覆写(override)这个getSalary方法:

    public double getSalary() {
        return salary + bonus;  
    }
    
    public double getSalary() {
        double baseSalary = getSalary();
        return baseSalary + bonus;   
    }
    
    public double getSalary() {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;  
    }

      这里给出了三个版本,其中第一,二个都是错误的,只有第三个是对的。第一个错在不能直接访问超类中的private属性salary,必须调用超类的getSalary方法。第二个版本错在它调用的是子类的getSalary方法,不是超类的,所以这个方法会无限循环执行。只有第三个是正确的。

      所以这里要记住:

      在子类中可以定义一个声明完全和超类一样的方法,这个叫做方法的覆写,当子类再次调用这个方法时,那执行的就是子类中定义的版本。

      另外,在子类中如果想要调用超类的方法,一定要在方法名字前加上super。

    构造方法 

      子类的构造方法的写法也是需要注意的。由于子类是无法直接访问超类中的private的数据域的,所以对于这些域,如果你想通过构造方法来为它们设定初值时,你就需要首先调用超类中的带参数构造方法,然后再为子类中特殊的域设置初值。

      比如我们写下Manager类的构造方法:

    1   public Manager(String name, double salary, double bonus) {
    2         super(name, salary);
    3         this.bonus = bonus;
    4   }

      其中第一句super就是调用超类中的带参数构造方法。这里要注意,这句super语句如果想这么使用,一定要把它放在第一句的位置。

      这里还有一点要注意:

      如果子类中没有显示的调用超类的构造方法,那么其实子类就会触发超类的无参数构造方法。如果超类中并不含有一个无参构造方法的话,那么子类还不显示的调用超类其他构造方法,那么java编译器就会报错。

      当前例子中Employee没有无参构造器,因为它已经有含参的了,所以如果在Manager中没有调用super方法,那么就会报错。所以这里的解决方案就是在Employee中再定义一个无参构造器。

    多态性 

      子类的对象可以被超类变量所引用,比如我们声明一个Employee引用,它引用的是一个子类对象:

    Employee boss = new Manager("Steve", 10000, 5000);
    System.out.println(boss.getSalary());

      但是这里要注意:采用超类变量引用是无法调用子类中的独有方法的,比如上面的例子中boss变量不能调用setBonus方法。

      然后我们再分析上例中第二句:

      如果超类变量调用了被子类所覆写的超类方法,则此时要执行的是子类中定义的版本!

      所以此时打印出来的是15000。说明即便Manager对象boss被Employee类变量所引用,但是JDK可以识别这个对象到底属于哪一类。所以才会输出正确的结果。

      之所以能实现这一点就是归功于jdk的动态绑定技术。 

      动态绑定技术是在java程序,对象的某个方法被调用时发生的技术。当某个对象引用调用这个对象的某个方法时,将会发生以下几步:

      1. 根据声明的方法名,遍历所有可能被调用的函数。

      2. 再根据输入参数的类型,确定最可能匹配的函数。如果没有或者是有多个,java都会报错。

      3. 如果方法是private,static,final或构造器时,那么被调用的方法直接执行,这个叫做静态绑定。否则的话,java会按照对象到底是属于什么类型来调用正确的方法。

      那么如果想让Employee类型的变量boss,调用setBonus方法怎么办?

      方法就是强制类型转换,把Employee类型的变量boss强制转换为Manager类型,如下

      Manager newBoss = (Manager) boss;
      newBoss.setBonus(4000);

      强制类型转换之前一般会做一次检查,检查一下要被转换的变量是否真的是要强制转换的类型,如果不是的话,会产生异常。检查的方法就是用instanceof方法:

    if(boss instanceof Manager)
        Manager newBoss = (Manager) boss;

    final修饰符

      如果不希望其他程序继承自自己的类,那么可以把这个类用final修饰符修饰,就可以防止其他类去继承它。

      如果不希望子类覆写超类的方法,那么在超类中可以把这个方法用final修饰符修饰一下。

    抽象类

      有的时候可能出现这种情况,好几个类都继承自同一个类,他们还有一个共同的方法,但是每一个类实现这个方法的方式都不一样。当这种问题发生时,你把这个方法的声明写在超类中还是子类中都是有不好的地方。所以这个时候就需要抽象类,抽象方法出场了。

       针对这种每个子类都有,但是却都实现方式不同的公有方法,我们可以把它在超类中声明成抽象方法即可。基本语法就是在这个方法的返回类型前面加上abstract修饰符。

       public abstract 返回类型 方法名(输入参数表)

       如果一个类中包含至少一个抽象方法的话,这个类也必须被声明为抽象类

       public abstract 类名 { ... }

       当然抽象类中不必所有方法都是抽象的,也可以有已经实现的。

       抽象类不能被实例化,一个类即便没有抽象方法也可以被声明为抽象的。当然抽象类的变量还是可以指向其非抽象的子类的。

  • 相关阅读:
    mybatis0206 延迟加载
    怎样关闭“粘滞键”?
    TNS-12557: TNS:protocol adapter not loadable TNS-12560: TNS:protocol adapter error
    HTTP协议头部与Keep-Alive模式详解
    oracle定时器执行一遍就不执行或本就不执行
    Inflation System Properties
    https://stackoverflow.com/questions/16130292/java-lang-outofmemoryerror-permgen-space-java-reflection
    java spring中对properties属性文件加密及其解密
    annotation配置springMVC的方法了事务不起作用
    SQLPlus在连接时通常有四种方式
  • 原文地址:https://www.cnblogs.com/fatsheep9146/p/5222500.html
Copyright © 2011-2022 走看看