当前位置: 首页 > news >正文

零基础 “入坑” Java--- 十、继承

文章目录

  • 一、何为继承
  • 二、继承语法
  • 三、父类成员访问
    • 1.成员变量
    • 2.成员方法
  • 四、super关键字
  • 五、子类构造方法
  • 六、super和this辨析
  • 七、再谈初始化
  • 八、protected关键字
  • 九、继承方式
  • 十、final关键字
  • 十一、继承与组合

根据我们学过的类的知识,我们来定义两个类:一个猫类,一个狗类:

class Dog {public String name;public int age;public String sex;public void eat() {System.out.println(this.name + "吃饭");}public void sleep() {System.out.println(this.name + "睡觉");}public void wang() {System.out.println(this.name + "汪汪叫");}
}
class Cat {public String name;public int age;public String sex;public void eat() {System.out.println(this.name + "吃饭");}public void sleep() {System.out.println(this.name + "睡觉");}public void miao() {System.out.println(this.name + "喵喵叫");}
}

仔细观察代码会发现,两个类中存在许多共性,代码就会比较冗余。为了解决这个问题,面向对象思想中提出了继承的概念,用于对共性进行抽取,实现代码复用,减少冗余。

一、何为继承

继承是面向对象思想中可以实现代码复用的一种重要手段,它允许程序员在保持原有类(父类/基类/超类) 的基础上进行扩展,增添新功能,由此产生的新的类,称为子类/派生类。

继承主要解决:对共性进行抽取,从而实现代码的复用。

二、继承语法

在Java中借助extends关键字实现继承关系,语法格式为:

修饰符 class 子类 extends 父类 {
//语句
}

我们根据语法对猫和狗类的共性进行抽取:

class Animal {public String name;public int age;public String sex;public void eat() {System.out.println(name + "吃饭");}public void sleep() {System.out.println(name + "睡觉");}
}
class Dog extends Animal {public void wang() {System.out.println(name + "汪汪叫");}
}
class Cat extends Animal {public void miao() {System.out.println(name + "喵喵叫");}
}

在继承时我们需要注意:

1.子类继承父类之后,会继承父类中的成员方法和成员变量(静态成员除外)。
2.子类继承父类之后,必须有子类独有的成员,需体现出与父类的不同,否则没必要继承。

三、父类成员访问

1.成员变量

我们可以在子类中直接访问从父类中继承下来的成员变量

class Fu {public int a;public int b;
}
class Zi extends Fu {public int c;public void test() {a = 10;b = 20;c = 30;System.out.println(a + " " + b + " " + c + " ");}
}
public class Test2 {public static void main(String[] args) {Zi zi = new Zi();zi.test();}
}

但是当父类和子类的成员变量名相同时,会访问哪个呢:

class Fu {public int a = 1;
}
class Zi extends Fu {public int a = 0;public void test() {System.out.println(a);}
}
public class Test2 {public static void main(String[] args) {Zi zi = new Zi();zi.test(); //0}
}

由运行结果可知:成员变量的访问遵循就近原则,如果子类中有,则优先使用子类的成员变量;如果子类中没有,则使用父类的成员变量;若父类和子类均没有,则编译报错。

2.成员方法

我们可以在子类中直接访问从父类中继承下来的成员方法

class Fu {public void test1() {System.out.println("嘻嘻");}
}
class Zi extends Fu {public void test2() {System.out.println("哈哈");}public void test() {test1();test2();}
}
public class Test2 {public static void main(String[] args) {Zi zi = new Zi();zi.test();}
}

但是当父类和子类的成员方法名相同时,会访问哪个呢:

class Fu {public void test1() {System.out.println("嘻嘻");}public void test2(int x) {System.out.println("xixi");}
}
class Zi extends Fu {public void test1() {System.out.println("哈哈");}public void test2() {System.out.println("haha");}public void test() {test1(); //哈哈test2(); //haha(调用子类)test2(666); //xixi(调用父类)}
}
public class Test2 {public static void main(String[] args) {Zi zi = new Zi();zi.test();}
}

由运行结果可知:成员方法的访问遵循就近原则,如果子类中有,则优先使用子类的成员方法;当父类和子类的 同名方法的 参数列表不同时,根据调用方法时传递的参数,选择合适的方法;如果子类中没有,则使用父类的成员方法;若父类和子类均没有,则编译报错。

但是当我们想在子类中访问父类的 同名的成员时,应该怎么办呢?此时,就可以使用super关键字。

四、super关键字

Java中提供了super关键字,帮助我们在子类中访问父类的成员。

class Fu {public int a = 1;public int b = 2;public int c = 3;
}
class Zi extends Fu {public int a = 11;public int d = 4;public void test() {System.out.println(a); //11System.out.println(b); //2System.out.println(c); //3System.out.println(d); //4System.out.println(super.a); //1}
}
public class Test2 {public static void main(String[] args) {Zi zi = new Zi();zi.test();}
}

在这里插入图片描述
对于super关键字:

1.如果super在当前类中被使用,则当前类一定为子类。
2.super只能访问从父类中继承过来的成员。
3.使用this访问,既可以访问父类成员也可以访问子类成员,但当访问父类和子类中同名的成员时,子类成员优先被访问。

因此,子类test方法中以下写法均正确:

        System.out.println(this.a); //11System.out.println(this.b); //2System.out.println(this.c); //3System.out.println(this.d); //4System.out.println(super.a); //1System.out.println(super.b); //2System.out.println(super.c); //3

注意:super关键字只能在非静态方法中使用!!!

五、子类构造方法

class Animal {public String name;public int age;public String sex;//一个参数的构造方法public Animal(String name) {this.name = name;}public void eat() {System.out.println(name + "吃饭");}public void sleep() {System.out.println(name + "睡觉");}
}
class Dog extends Animal {public void wang() {System.out.println(name + "汪汪叫");}
}

我们为动物类提供带有一个参数的构造方法,此时狗类继承动物类时,就会报错。这是因为:当子类继承父类之后,需要先帮助父类进行构造,再构造子类自己。 那又如何帮助父类进行构造呢:在子类中调用父类的构造方法。

构造方法的作用就是对 对象中的成员变量进行初始化,因此需要先调用父类的构造方法,对从父类继承下来的成员完成构造,再调用子类自己的构造方法,对子类中独有的成员进行构造。

于是,我们对代码进行修改:

class Animal {public String name;public int age;public String sex;public Animal(String name) {this.name = name;}public void eat() {System.out.println(name + "吃饭");}public void sleep() {System.out.println(name + "睡觉");}
}
class Dog extends Animal {public Dog(String name) {super(name);}public void wang() {System.out.println(name + "汪汪叫");}
}

在这里插入图片描述
总结一下:

1.当父类显式定义无参或者使用默认提供的构造方法时,子类构造方法的第一行均默认有隐藏的super()调用,即调用父类构造方法。
2.如果父类的构造方法带有参数,则需要显式定义子类的构造方法,并在子类构造方法中调用合适的父类构造方法。
3.在子类构造方法中,super()只能出现在子类构造方法的第一行,因此子类构造方法中只能出现一次super()。

六、super和this辨析


【相同点】
1.均为Java中的关键字。
2.均可以对成员进行访问,且super()和this()都需要在构造方法的首行使用,因此不能同时存在于同一个构造方法。
3.只能在类的非静态方法中使用,用于访问非静态的成员。


【不同点】
1.this代表当前对象的引用,当前对象即调用成员的对象;super代表在子类对象中 对从父类继承下来的成员 的引用。
2.在非静态成员方法中,this既可以访问子类的成员,也可以访问父类的成员;super只能访问父类的成员。
3.在构造方法中,this()用于调用当前类中的构造方法;super()用于调用父类的构造方法。
4.当子类继承父类后,子类的构造方法中一定会存在super()语句,哪怕没有显式定义,编译器也会自动添加;this()不写则没有。


七、再谈初始化

在上一章节中,我们已经学习了有关代码块的知识。在继承关系中,各个代码块的执行顺序又是怎样的呢?

class Animal {public String name;public int age;public String sex;public Animal(String name) {this.name = name;System.out.println("动物构造");}static {System.out.println("动物静态代码块");}{System.out.println("动物实例代码块");}
}
class Dog extends Animal {public Dog(String name) {super(name);System.out.println("小狗构造");}static {System.out.println("小狗静态代码块");}{System.out.println("小狗实例代码块");}
}
public class Test {public static void main(String[] args) {Dog dog1 = new Dog("小狗1");System.out.println("======================");Dog dog2 = new Dog("小狗2");}
}

运行结果为:
在这里插入图片描述
由运行结果我们可以得出:

1.静态代码块优先执行,且父类优先于子类执行。
2.父类的实例代码块和构造方法其次执行。
3.子类的实例代码块和构造方法最后执行。
4.静态代码块只执行一次,第二次实例化对象时,父类和子类的静态代码块均不再执行。

八、protected关键字

在这里插入图片描述
依旧是这张图片,我们来学习一下protected关键字。
在这里插入图片描述


在这里插入图片描述


学习了继承之后,我们对private关键字再补充一点:在父类中被private修饰的成员虽然在子类中不能直接访问,但是也继承到了子类中。

九、继承方式

在Java中支持单继承、多层继承、不同类继承同一个类,但不支持多继承!!!
在这里插入图片描述

十、final关键字

final关键字可以用来修饰变量、方法和类。

final修饰变量时,表示变量不能被修改,即常量:

    public static void main(String[] args) {final int a = 10;a = 20; //×}

final修饰类时,代表类不能被继承:

final class A {
}
//错误×
class B extends A {
}

被final修饰的类,也叫密封类。

final还可以修饰方法,这一点我们以后再介绍。


我们来看一段代码:

        final int[] array = {1,2,3,4,5};array = new int[10]; //1array[0] = 10; //2

这段代码会在1处报错:
在这里插入图片描述

十一、继承与组合

如果将继承比作is-a的关系,那么组合就是has-a的关系。

组合和继承类似,也是一种表达类和类之间关系的方式,也可以达到代码复用的效果。组合的思想体现在代码上 就是将一个类的实例作为另一个类的成员变量,并无特殊的语法格式:

class Old {}
class Home {public Old[] olds;public Home() {this.olds = new Old[2];}
}

Ending。

http://www.dtcms.com/a/277073.html

相关文章:

  • ARC 03 从Github Action job 到 runner pod
  • PPO(近端策略优化)
  • 华为HarmonyOS 5.0深度解析:跨设备算力池技术白皮书(2025全场景智慧中枢)
  • 【C++】list及其模拟实现
  • C++--List
  • AI交互中的礼貌用语:“谢谢“的效用与代价分析
  • 【操作系统-Day 5】通往内核的唯一桥梁:系统调用 (System Call)
  • MVC 参考手册
  • C++值类别与移动语义
  • linux shell从入门到精通(一)——初识Shell程序
  • opencv中contours的使用
  • Spring Boot RESTful API 设计指南:查询接口规范与最佳实践
  • Docker从环境配置到应用上云的极简路径
  • 【Docker基础】Dockerfile指令速览:文件与目录操作指令详解
  • 【深度学习新浪潮】什么是新视角合成?
  • Python----OpenCV(图像分割——彩色图像分割,GrabCut算法分割图像)
  • 【Linux】线程机制深度实践:创建、等待、互斥与同步
  • ARC 02 runner scale set chart:对接集群与 Github Action 服务器
  • Linux|服务器|二进制部署nacos(不是集群,单实例)(2025了,不允许还有人不会部署nacos)
  • 速通TypeScript装饰器
  • 【windows办公小助手】比文档编辑器更好用的Notepad++轻量编辑器
  • 机器学习sklearn入门:使用KNN模型分类鸢尾花和简单调参
  • 分类问题-机器学习
  • 「小程序开发」项目结构和页面组成
  • Http与Https区别和联系
  • 13. Flink 高可用机制简述(Standalone 模式)
  • 单页面和多页面的区别和优缺点
  • phpMyAdmin:一款经典的MySQL在线管理工具又回来了
  • 数学建模:评价决策类问题
  • 【nRF52832】【Ble 1】【低功耗蓝牙简介】