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

  在这里我们通过一个实例来讲解继承的基本知识。假设我们在为一个公司设计一个管理系统,管理公司的人员,我们首先定义了一个雇员类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类是最合适不过的。

 public Manager extends Employee {

     private double bonus;

     public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
} public double getBonus() {
return bonus;
} public void setBonus(double bonus) {
this.bonus = bonus;
}
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类的构造方法:

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

  其中第一句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 类名 { ... }

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

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

Java基础知识点4:继承的更多相关文章

  1. Java基础知识点(三)

    前言:准备将Java基础知识点总结成一个系列,用于平常复习并加深理解.每篇尽量做到短小精悍,便于阅读. 1.Math类中相关函数 Math.floor(x):返回不大于x的最大整数.eg:Math.f ...

  2. Java基础知识点(二)

    前言:Java的基础知识点不能间断. 1.Array和ArrayList的区别 关于Array的用法,参看:http://blog.csdn.net/b_11111/article/details/5 ...

  3. Java基础知识点(一)

    前言:本篇随笔,主要记录Java的基础知识点,不管是用于项目或者面试中,笔者认为都非常有用,所以将持续更新...... 1.Java的访问权限 Java中有四种访问权限:默认访问权限.public.p ...

  4. Java基础知识点总结

    前言 本文主要是我之前复习Java基础原理过程中写的Java基础知识点总结.Java的知识点其实非常多,并且有些知识点比较难以理解,有时候我们自以为理解了某些内容,其实可能只是停留在表面上,没有理解其 ...

  5. JAVA基础知识点总结(全集)

    1.JAVA简介 1.1java体系结构:j2se,javaweb,j2ee 1.2java特点:平台无关(虚拟机),垃圾回收(使得java更加稳定) 1.3 JDK与JRE,JDK:java开发环境 ...

  6. Java基础知识点(四)

    前言:记录Java基础知识点,方便熟悉与掌握. 1.面向对象的"六原则一法则" “六原则一法则”:单一职责原则.开闭原则.依赖倒转原则.里氏替换原则.接口隔离原则.合成聚合复用原则 ...

  7. java基础知识点补充---二维数组

    #java基础知识点补充---二维数组 首先定义一个二维数组 int[][] ns={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16} }; 实现遍 ...

  8. Java 基础知识点

    很多 Java 基础的东西都忘记了, 有必要再复习一些基本的知识点. 本文主要参考 https://github.com/Snailclimb/JavaGuide ================== ...

  9. Java基础知识点

    以下10点为JAVA 基础知识,后面将足以总结和完善以备面试 数据类型 (包装类,字符串,数组) 异常处理 Java IO和NIO 数据结构 (集合和容器 ) 多线程(并发) 网络通信(协议) 面向对 ...

  10. Java基础笔记-抽象,继承,多态

    抽象类: abstract修饰 抽象方法必须定义在抽象类中,抽象类不能创建对象. 在抽象方法中可以不定义抽象方法,作用是:让该类不能建立对象. 特点是: 1.定义在抽象类中 2.方法和类都用abstr ...

随机推荐

  1. 没有素描色彩基础适合学习UI吗,如果可以,该怎么学?

      文章背景,来自[ UI设计交流群 - 92588284 ]的一次探讨,由于个人视野有限,个中观点有失狭隘,仅供参考,欢迎拍砖: 问题一:一个朋友想学UI设计,没有任何基础的,也没有美术功底,想问问 ...

  2. 一张图告诉你,只会HTML还不够!

    会了HTML和HTML5语法,你就真的会了HTML吗,来看这张图!是这本<超实用的HTML代码段>入门实例书的导览!熊孩子们,赶紧学习去吧! 如果一半以上的你都不会,必须看这本书,阿里一线 ...

  3. PHP之readdir()函数

    最近在学习php文件操作的相关知识,记录一下readdir()函数其中的一个要注意的点 1. 在$temp=readdir($handle)函数中 readdir获取的是文件名和$handle中的文件 ...

  4. MySQL中的常用工具

    一.mysql 客户端连接工具 二.myisampack MyISAM表压缩工具 三.mysqladmin MySQL管理工具 四.mysqlbinlog 日志管理工具 五.mysqlcheck My ...

  5. js面向对象

    什么事面向对象 用对象的思想去写代码,就是面向对象编程 面向对象编程(OOP)的特点 抽象:抓住核心问题 封装:只能通过对象来访问方法 继承:从已有对象上继承出新的对象 多态:多对象的不同形态 对象的 ...

  6. WPF菜单

    1.Menu Menu 是水平放置它的项的,默认情况下把灰色栏作为背景. 把Menu 添加到它的ItemsControl 基类的唯一公开的API 是IsMainMenu 属性.当为true(默认的)时 ...

  7. bootstrap的table调用本列ID

    我们是用json解析数据. 后台传送data数据~ String data = JSON.toJSONString(baseInfoService.list());request.setAttribu ...

  8. 【阿里云配置端口开放】使用 iptables

    要知道: 1.目前(16年-12-10)阿里云主机只要有服务开启,所有端口是默认开启的.这样很不好,安全做法是,需要开启外网端口时,由开发人员去配置. 2.想要开放端口,就需要使用iptables命令 ...

  9. appium V1.5.x变化

    使用 npm安装 appium之后,会发现已经进入1.5 [Appium] Welcome to Appium v1.5.0 [Appium] Appium REST http interface l ...

  10. 三妹,我拆了你的本-- Day One(大图赏)

    从垃圾箱中捡到了三妹的笔记本,虽然显卡已烧,硬盘和内存已被掳走,但依旧很高兴的说,因为我的目的是要拆了它. 这是我的第一次,所以本文的内容完全是新手猎奇,高手勿喷~ 步骤1:拆掉塑料外壳 不要忘了硬盘 ...