多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。其中如图中所示,食草动物、食肉动物、兔子、羊、狮子、豹都可以称为子类,动物类称为父类、超类(superclass)或者基类。

继承描述的是事物之间的所属关系。例如,图中兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。

继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

修饰符 class 父类 {
  ...
}

修饰符 class 子类 extends 父类 {
  ...
}

来一个例子:

// 父类
public class Animal {
String name;
public void eat(){
System.out.println("肚子饿了都要吃东西");
}
} // 子类继承父类
public class Lion extends Animal{
public void printName(){
System.out.println("名字:"+ name);
}
} // 测试类
public class Demo {
public static void main(String[] args) {
// 创建一个狮子类对象
Lion lion = new Lion();
// 为该Lion类的name属性进行赋值
lion.name = "狮子王";
// 调用该Lion类的printName()方法
lion.printName(); // 名字:狮子王
// 调用从Animal类继承来的eat()方法
lion.eat(); // 肚子饿了都要吃东西
}
}

通过上面代码我们可以看出用继承的方式可以 提高代码的复用性。同时类与类之间产生了关系,是多态的前提,这个在接下来的章节说明。

继承后的特点

当类之间产生了关系后,其中各类中的成员变量和成员方法会产生了哪些影响呢?

一、成员变量

1、成员变量不重名

如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。

public class Fu {
// Fu中的成员变量。
int numFu = 10;
} public class Zi extends Fu {
// Zi中的成员变量
int numZi = 20;
// Zi中的成员方法
public void show() {
  // 访问父类中的numFu,继承而来可以直接访问
  System.out.println("Fu numFu="+numFu);
  // 访问子类中的numZi
  System.out.println("Zi numZi="+numZi);
  }
} public class Demo {
public static void main(String[] args) {
// 创建子类对象
Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
} 演示结果:
Fu num1 = 10
Zi num2 = 20

2、成员变量重名

public class Fu {

    int numFu = 10;

    int num = 100;

    public void methodFu() {
System.out.println(num);
} } public class Zi extends Fu { int numZi = 20; int num = 200; public void methodZi() {
System.out.println(num);
} } public class Demo { public static void main(String[] args) {
Fu fu = new Fu();
System.out.println(fu.numFu); // Zi zi = new Zi();
System.out.println(zi.numFu); //
System.out.println(zi.numZi); // 20 // 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找。
System.out.println(zi.num); // 优先子类,200
System.out.println(zi.abc); // 到处都没有,编译报错! //间接通过成员方法访问成员变量:该方法属于谁,就优先用谁,没有则向上找。
zi.methodZi(); // 200, 这个方法是子类的,优先用子类的没有再向上找
zi.methodFu(); // 100,这个方法是在父类当中定义的,
} }

从上面代码来看,想用父类的num值又怎么办呢?

子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量,类似于之前学过的 this 。

使用格式:super.父类成员变量名

因此子类的代码可以写为:

public class Zi extends Fu {// Zi中的成员方法
public void show() {
System.out.println("Fu num="+super.num);
System.out.println("Zi num="+num);
}
} 演示结果:
Fu num = 100
Zi num = 200

注意事项:

  (1)Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?

  答案是可以在父类中提供公共的getter方法和setter方法。

  (2)局部变量: 直接写成员变量名

  (3)本类的成员变量: this.成员变量名

  (4)父类的成员变量: super.成员变量名

因此子类的代码又可以修改为:

public class Zi extends Fu {// Zi中的成员方法
public void show() {
int innerNum = 10; // 局部变量
System.out.println("Fu num="+super.num);
System.out.println("Zi num="+this.num);
System.out.println("innerNum="+innerNum);
}
}

二、成员方法

1、成员方法不重名

public class Fu {

    public void methodFu() {
System.out.println("父类方法执行!");
} } public class Zi extends Fu { public void methodZi() {
System.out.println("子类方法执行!");
} } public class Demo {
public static void main(String[] args) { Zi zi = new Zi(); zi.methodFu();
zi.methodZi();
}
} 运行结果:
父类方法执行!
子类方法执行!

如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。

2、成员方法重名

先来一波代码:

public class Fu {

    public void methodFu() {
System.out.println("父类方法执行!");
} public void method() {
System.out.println("父类:重名方法执行!");
} } public class Zi extends Fu { public void methodZi() {
System.out.println("子类方法执行!");
} public void method() {
System.out.println("子类:重名方法执行!");
} } public class Demo01ExtendsMethod { public static void main(String[] args) {
Zi zi = new Zi();
zi.method(); // 子类:重名方法执行!
} }

上述代码中因为子类又method成员方法,所以执行了子类的method方法。其实跟之前的重名的成员变量类似:看子类有没有,没有就向父类查找。

重写

其实如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)

方法重写 :子类中出现与父类一模一样的方法时(返回值类型、方法名、参数列表都相同)会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。

注意区分重写(Override)和重载(Overload):

重写(Override):方法的名称一样,参数列表【也一样】。
重载(Overload):方法的名称一样,参数列表【不一样】。
更优雅的覆盖重写的方式:
public class Fu {

    public void methodFu() {
System.out.println("父类方法执行!");
} public void method() {
System.out.println("父类:重名方法执行!");
} } public class Zi extends Fu { public void methodZi() {
System.out.println("子类方法执行!");
} @Override
public void method() {
System.out.println("子类:重名方法执行!");
} }
方法覆盖重写的注意事项:
(1) 必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求也是正确的方法覆盖重写。
(2)子类方法的返回值必须【小于等于】父类方法的返回值范围。
(3)子类方法的权限必须【大于等于】父类方法的权限修饰符。
public > protected > (default) > private,实例代码如下:
public class Fu {
// 没写权限修饰符,就是default
void method(){
System.out.println("父类成员方法!");
} } public class Zi extends Fu{ @Override
public void method(){
System.out.println("子类成员方法!");
} }
(4)用到 super.父类成员方法(),表示调用父类的成员方法,如:
public class Zi extends Fu {

    public void methodZi() {
System.out.println("子类方法执行!");
} public void method() {
super.method();
} }

 三、构造方法

当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?

构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:

public class Fu {

    public Fu() {
System.out.println("父类无参构造方法!");
} public Fu(int num) {
System.out.println("父类有参构造方法!");
} } public class Zi extends Fu { public Zi() {
super(); // 在调用父类无参构造方法
System.out.println("子类无参构造方法!");
} } public class Demo { public static void main(String[] args) {
new Zi();
} } 运行结果:
父类无参构造方法!
子类无参构造方法!
继承关系中,父子类构造方法的访问特点:
(1)子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造后执行的子类构造。看代码:
public class Fu {
public Fu(){
System.out.println("父类无参构造方法!");
}
public Fu(int num){
System.out.println("父类有参构造方法!");
}
} public class Zi extends Fu{
public Zi(){
System.out.println("子类无参构造方法!");
}
} public class Demo {
public static void main(String[] args) {
new Zi();
}
} 运行结果:
父类无参构造方法!
子类无参构造方法!
(2)子类构造可以通过super关键字来调用父类重载构造。
(3)super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。代码如下:
public class Zi extends Fu{
public Zi(){
System.out.println("子类无参构造方法!");
}
public void method(){
// 错误写法,写在了子类成员方法中
super(200)
System.out.println("子类成员方法!");
}
} 或者 public class Zi extends Fu{
public Zi(){
// 错误写法,存在了两个super
super();
super(200);
System.out.println("子类无参构造方法!");
}
} 或者 public class Zi extends Fu{
public Zi(){
System.out.println("子类无参构造方法!");
// 错误写法,super应该写在第一个语句
super(200);
}
}
因此,子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

四、super和this

父类空间优先于子类对象产生

在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。理解图解如下:

1、super和this的含义

super :代表父类的存储空间标识(可以理解为父亲的引用)。
this :代表当前对象的引用(谁调用就代表谁)。

2、super和this的用法

(1)访问成员

this.成员变量 ‐‐ 本类的

super.成员变量 ‐‐ 父类的

this.成员方法名() ‐‐ 本类的

super.成员方法名()  --  父类的

(2)访问构造方法

this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法

五、继承的特点

1、Java只支持单继承,不支持多继承

//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error

2、Java支持多层继承(继承体系)

class A{}
class B extends A{}
class C extends B{}

顶层父类是Object类。所有的类默认继承Object,作为父类。并且子类和父类是一种相对的概念。

【Java】面向对象之继承的更多相关文章

  1. Java面向对象之继承(一)

    目录 Java面向对象之继承 引言 继承的特点 语法格式 父子类的关系 继承要点 重写父类方法 继承中的构造器 继承中的super关键字 ... Java面向对象之继承 继承是面向对象的第二大特征,是 ...

  2. Java面向对象的继承

    继承也是面向对象的又一重要特性,继承是类于类的一种关系,通俗来说狗属于动物类,那么狗这个类就继承了动物类 java中的继承是单继承的,一个类只能继承与一个父类 子类继承父类之后,子类就拥有了父类的所有 ...

  3. JAVA面向对象之继承

    继承: 子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法 class 子类 extends 父类 { } 继承的特性: 子类拥有父类非private的属性,方法. 子类可以拥有自己 ...

  4. Java:[面向对象:继承,多态]

    本文内容: 继承 多态 首发时期:2018-03-23 继承: 介绍: 如果多个类中存在相同的属性和行为,可以将这些内容抽取到单独一个类中,那么多个类(子类)无需再定义这些属性和行为,只要继承那个类( ...

  5. Java面向对象之继承extends 入门实例

    一.基础概念 (一)继承的好处: 1.继承:提高了代码的复用性. 2.让类与类之间产生了关系,给多态这个特征提供了前提. (二)继承的种类: 1.单继承:一个类只能有一个父类. 2.多继承:一个类可以 ...

  6. Java面向对象_继承——基本概念以及管理化妆品实例分析

    一.继承的基本概念: 1.继承是面向对象三大特征之一 2.被继承的类成为父类(超类),继承父类的类成为子类(派生类) 3.继承是指一个对象直接使用另一个对象的属性和方法 4.通过继承可以实现代码重用 ...

  7. Java面向对象(继承、抽象类)

    面向对象 今日内容介绍 u 继承 u 抽象类 第1章 继承 1.1 继承的概念 在现实生活中,继承一般指的是子女继承父辈的财产.在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成 ...

  8. java面向对象之 继承 Inheritance

    对象的一个新类可以从现有的类中派生,这个过程称为类继承.新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类).派生类可以从它的基类那里继承方法和实例变量,并且类可以修 ...

  9. Java 面向对象之继承和重写OverWrite,重写和重载的区别,抽象类

    01继承的概述 A:继承的概念 a:继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系 b:在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作 ...

  10. Java面向对象之继承,方法重写,super关键字,员工类系列继承题

    在程序中,如果想声明一个类继承另一个类,需要使用extends关键字. 格式: class 子类 extends 父类 {} 继承的好处 1.继承的出现提高了代码的复用性,提高软件开发效率. 2.继承 ...

随机推荐

  1. 素数与Miller-Rabin测试

    素数及其性质 素数又称质数.指整数在一个大于 111 的自然数中,除了 111 和此整数自身外,没法被其他自然数整除的数. 性质1 有无穷多个素数. 证明: 用反证法.设已知的最大素数为 PPP,考虑 ...

  2. Github 高级搜索功能

    参考文章链接:https://zhuanlan.zhihu.com/p/55294261 GitHub 提供高级搜索方式. 一.明确搜索仓库标题.仓库描述.README 1.只想查找仓库名称包含XX的 ...

  3. openssl之DH(Diffie–Hellman)加密

    //加密机制初始化 g_HDMgr.init(); //对方的public key BIGNUM* peerPubKey = NULL; peerPubKey = BN_bin2bn((unsigne ...

  4. ride.py 启动报错

    报错问题: C:\Users\iphauser>ride.py Traceback (most recent call last): File , in OnInit self._plugin_ ...

  5. 网络攻防实验任务三_(2)X-Scan通用漏洞扫描实验

    首先在宿主机中打开xscan_gui.exe,结果系统直接将它删掉了. 大概是因为开了防火墙的缘故. 于是我在win7虚拟机中运行这个程序. 并且关闭防火墙,在win7中可以运行 我再试了一下win1 ...

  6. 【网络安全】Dos攻击科普文

    目录 DOS攻击 什么是DOS攻击 攻击手段分类 具体的攻击方式举例 优秀博客参考 DDOS攻击 DOS攻击 什么是DOS攻击 DOS是Denial of Service的简称,用中文简单翻译就是拒绝 ...

  7. redis集群之Codis

    在大数据高并发场景下,单个 Redis 实例往往会显得捉襟见肘.首先体现在内存上,单个 Redis 的内存不宜过大,内存太大会导致 rdb 文件过大,进一步导致主从同步时全量同步时间过长,在实例重启恢 ...

  8. Spring(四)Spring与数据库编程

    Spring最重要的功能毫无疑问就是操作数据.数据库的百年城是互联网编程的基础,Spring为开发者提供了JDBC模板模式,那就是它自身的JdbcTemplate.Spring还提供了Transact ...

  9. python wraps的作用

    1.__name__用来显示函数的名称,__doc__用来显示文档字符串也就是("""文档字符串""")这里面的内容 2.首先我们来看不加@ ...

  10. SpringBoot整合MybatisPlus3.X之乐观锁(十三)

    主要适用场景 意图: 当要更新一条记录的时候,希望这条记录没有被别人更新 乐观锁实现方式: 取出记录时,获取当前version 更新时,带上这个version 执行更新时, set version = ...