带你玩转java封装和继承(上)

上次带大家学习了java里面比较重要的知识点类和对象,而且我们知道java是一门面向对象的语言,有时一个程序里可能有很多类,那么这么多类他们之间有什么联系吗?今天就带大家学习一下java类之间的关系。

 

 什么是继承:

我们在日常学习中,在java程序编写时,先创建类,在实例化对象进一步对类进行使用,然而,世界上很多事物往往都不是独立的,他们之间可能存在着千丝万缕的联系,那么如何建立这种联系呢

举个例子创建一个狗类:

//Dog类
public class Dog{
  String name;
  String sex;
  int age;
    public void bark(){
      System.out.println(name+"正在汪汪汪");
   }
   public void sleep(){
      System.out.println(name+"正在睡觉")
   }
}

在定义一个猫类:

public class Cat{
string name;
int age;
string color;
public void sleep()
{
System.out.println(name + "正在睡觉");
}
void mew(){
System.out.println(name + "喵喵喵~~~");
}
}

通过这两个例子我们可以很直观的看到,这两类有太多一样的地方,我们如果可以把这些一样的部分抽离出来,使用时直接调用它,代码效率会大大加强,实现了代码的复用,其实,这就是继承的本质。

继承 (inheritance) 机制 :是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性 的基础上进行扩展,增加新功能 ,这样产生新的类,称 派生类 。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码用
例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。
概念可能不太直观,这里我以上面为例,重新写一段程序:

 

public class Animal{
   String name;
   int age;
  public void eat(){
    System.out.println(name+"正在吃饭");
  }
  public void sleep(){
    System.out.println(name+"正在睡觉");
  }
}
public class Dog extends Animal{
  void bark(){
    System.out.println(name + "汪汪汪~~~");
  }
}
public class Cat extends Animal{
  void mew(){
    System.out.println(name + "喵喵喵~~~");
 }
}

       我们将Dog类和Cat类称为子类,Animal为父类。 

       这样的话,代码就大大简化当我们再去创建动物对象时,就可以直接调用这里的Animal类中的成员这里的extends是子类继承父类成员时必须使用的关键字。

子类如何访问父类的成员:

子类访问父类的成员,这里分为两种情况:

  1. 子类成员与父类成员名字一致。
  2. 子类成员与父类成员名字不一致。

 子类成员与父类成员名字一致

public class Base {
int a;
int b;
int c;
}
/
public class Derived extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; // 访问父类继承的a,还是子类自己新增的a?
b = 101; // 访问父类继承的b,还是子类自己新增的b?
c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
// d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
}
}

这里需要注意的是:

  1. 当父类与子类成员名字一致时,优先访问自己的成员变量。
  2. 当访问成员变量时优先访问自己的,若没有再去访问父类的
  3. 若子类与父类都没有,会发生编译错误。

成员变量是这样,成员方法也是这样,调用成员方法时优先考虑子类自己的,若没有则去父类中查找,都没有就会报错。

public class Base {
public void ways1(){
System.out.println("Base中的ways1()");
}
public void ways2(){
System.out.println("Base中的ways2()");
}
}
public class Derived extends Base{
public void ways1(int a) {
System.out.println("Derived中的way1(int)方法");
}
public void ways2(){
System.out.println("Derived中的ways2()方法");
}
public void ways3(){
ways1(); // 调用的是父类中的因为,父类中午参数
ways1(20); // 传递参数,访问子类中的way1(int)
ways2(); //默认访问子类中的ways2
}
}

 super关键字

上面我们说了,当访问的成员或变量子类与父类同名时,默认访问的是子类的,那么如果就像访问父类的呢?这里就需要使用到super关键字了。他可以在子类方法中访问父类的成员

 

class Country {
    String name;
    void value() {
       name = "China";
    }
}
  
class City extends Country {
    String name;
    void value() {
    name = "Shanghai";
    super.value();      //调用父类的方法
    System.out.println(name);   //默认打印子类中的china
    System.out.println(super.name);   //使用super关键字调用父类中的name
    }
  
    public static void main(String[] args) {
       City c=new City();
       c.value();
       }
}

运行结果: Shanghai     China   

在子类方法中,如果想要明确访问父类中成员时,借助super关键字即可。
注意:
  1. super关键字只可以在非静态的方法中访问。
  2. super关键字是在子类中调用父类成员使用的。

子类的构造方法

我们在实例化子类对象时,会调用子类的构造方法,然而其实子类的构造方法在调用之前,编译器已经偷偷地将父类的构造方法调用过一次了,只是没有显示而已,我们可以这样理解,子类中的成员变量,其实是由两部分构成的,一部分是自己的,另一部分是从父类中继承下来的,所以必须先要把从父类中继承的成员变量初始化了,然后才初始化自己的成员变量。

正所谓:父子父子,先有父才能有子。

public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
// super(); 
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}

运行结果:Base()   Derived()

总结:

  1. 当父类中显式定义无参或者默认的构造方法,那么在子类中都默认调用了父类无参数的构造方法。
  2. 当自行定义有参数的父类构造方法时,子类的构造方法中不在默认提供调用父类构造方法的操作。需要用户在子类的构造方法中自行调用,否则编译错误。
  3. 当在子类中调用super(),必须将super()放到第一行,否则编译错误。
  4. 在子类的构造方法中不能同时出现super()和this因为从语法上他们都要放到第一行。

 super和this的区别

这里提醒一下,不懂this的uu们,看我的上一篇文章。

this 相当于是指向当前对象本身,可以理解为指向当前对象的指针,(当然java中没有指针只是这样方便理解)。

这里介绍this的几种用法:

  1. .普通的直接引用:直接使用this.×××来引用
  2. 当类中的成员变量与成员函数中的参数同名时,this.成员变量,用来指代当前对象的引用
    class Person {
        private int age = 10;
        public Person(){
        System.out.println("初始化年龄:"+age);
    }
        public int GetAge(int age){
            this.age = age;   //调用的是当前对象Harry的age=形参的age
            return this.age;
        }
    }
     
    public class test1 {
        public static void main(String[] args) {
            Person Harry = new Person();
            System.out.println("Harry's age is "+Harry.GetAge(12));
        }
    }
  3. 用来调用另一种构造方法:
    
        
    public class Chinese { 
        Chinese() { 
          
           System.out.println("无参数构造方法"": "+"A chinese coder."); 
        } 
        
        Chinese(String name) { 
          
           System.out.println("含一个参数的构造方法"": "+"his name is " + name); 
        } 
        
        Chinese(String name, int age) { 
           this(name);// 调用具有相同形参的构造方法(3) 
           System.out.println("两个形参的构造方法:his age is " + age); 
        } 
        
        public static void main(String[] args) { 
           Chinese cn = new Chinese(); 
           cn = new Chinese("codersai"); 
           cn = new Chinese("codersai", 18); 
        } 
    }

    super可以理解为一个指向父类对象的指针,完成对父类对象的引用。

    普通的直接引用:super.×××引用父类对象的成员变量

    子类中的成员变量或方法与父类中的成员变量或方法同名:使用super.×××来调用父类的成员。

    引用构造函数:子类中的构造方法执行之前要先调用父类中的super(),且必须是第一行。

初始化代码运行顺序

静态代码块执行    实例代码块执行       构造方法执行

这三种代码块的运行顺序是怎么样的呢,

class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
public class TestDemo4 {
public static void main(String[] args) {
Student student1 = new Student("张三",19);
System.out.println("===========================");
Student student2 = new Student("ningzhiyuan",20);

运行结果:

Person :静态代码块执行
Student :静态代码块执行
Person :实例代码块执行
Person :构造方法执行
Student :实例代码块执行
Student :构造方法执行
===========================
Person :实例代码块执行
Person :构造方法执行
Student :实例代码块执行
Student :构造方法执行

       由此我们知道了代码块的执行顺序:父类静态代码块,子类静态方法,父类实例代码块 ,父类构造方法,子类实例代码块,子类构造方法。并且静态代码块只执行一次。

访问限定符

java中为了更好的封装,建立了访问限定符,让数据封装起来,数据更加安全。

 

这些限定符决定了数据在哪里可以使用,哪里不可以使用,对于数据权限的管理非常有效。也提醒我们后面使用数据之前应该了解数据的权限避免写出错误的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/422808.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】实现栈

大家好,我是苏貝,本篇博客带大家了解栈,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 一 .栈的概念及结构二 .栈的实现栈的结构体初始化销毁栈顶插入栈顶删除显示栈顶元素是否为空栈的大…

2673. 使二叉树所有路径值相等的最小代价

给你一个整数 n 表示一棵 满二叉树 里面节点的数目,节点编号从 1 到 n 。根节点编号为 1 ,树中每个非叶子节点 i 都有两个孩子,分别是左孩子 2 * i 和右孩子 2 * i 1 。 树中每个节点都有一个值,用下标从 0 开始、长度为 n 的整…

c++之旅——第二弹

大家好啊,这里是c之旅第二弹,跟随我的步伐来开始这一篇的学习吧! 如果有知识性错误,欢迎各位指正!!一起加油!! 创作不易,希望大家多多支持哦! 一、内存四区…

等概率事件算法

1等概率的生成(0-8)范围内的正整数 // Math.random 数据范围[0,1) 且 是 等概率的产生随机数 // 应用: // 1.生成等概率的整数(等概率的生成(0-8)范围内的正整数 int value (int) (Math.random() * 9); System.out.println("value "…

Python 教学平台,支持“多班教学”的课程授课方式|ModelWhale 版本更新

龙行龘龘、前程朤朤,ModelWhale 新一轮的版本更新,期待为大家带来更优质的使用体验。 本次更新中,ModelWhale 主要进行了以下功能迭代: 新增 课程(包括课件、作业、算力)按班级管理(团队版✓ …

基于Google Vertex AI 和 Llama 2进行RLHF训练和评估

Reinforcement Learning from Human Feedback 基于Google Vertex AI 和 Llama 2进行RLHF训练和评估 课程地址:https://www.deeplearning.ai/short-courses/reinforcement-learning-from-human-feedback/ Topic: Get a conceptual understanding of Reinforcemen…

程序员的金三银四求职宝典!

目录 ​编辑 程序员的金三银四求职宝典 一、为什么金三银四是程序员求职的黄金时期? 二、如何准备金三银四求职? 1. 完善简历 2. 增强技术能力 3. 提前考虑目标公司 4. 提前准备面试 三、程序员求职的常见面试题 1. 数据结构和算法 2. 数据库 …

文件系统制作

文章目录 什么是文件系统如何制作根文件系统文件添加登录密码文件系统制作Squashfs制作方式gzip & lzo & xz 压缩 Jffs2制作方式 Ubi文件系统 什么是文件系统 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构&am…

el-input组件当数据为空时, 边框变红,并提示错误信息

1&#xff0c;样式 初始&#xff1a; 当不输入口令&#xff0c; 点击确定时&#xff1a; 2, 思路 主要是使用动态类的方式。 先设置输入框变红的样式以及提示文字的样式class 对于样式class 用变量来控制是否奏效。 3&#xff0c; 代码实现 //html&#xff1a; <div cl…

数据结构-----反射

文章目录 反射1.定义2 用途(了解)3 反射基本信息4 反射相关的类&#xff08;重要&#xff09;4.1 Class类(反射机制的起源 )4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中) 4.2 反射示例4.2.1 获得Class对象的三种方式4.2.2 反射的使用 5、反射优点和缺点6 重点总…

七、基于FreeRTOSSTM32移植MQTT

1、移植环境 (1)Keil MDK: V5.38.0.0 (2)STM32CubeMX: V6.8.1 (3)MCU: STM32F407ZGT6 (4)已移植好FreeRTOS和调试好串口的项目。 FreeRTOS移植参考博客&#xff1a;示例1&#xff1a;FreeRTOS移植详解_基于HAL库工程_hal库移植rtos-CSDN博客mqttclient源码&#xff1a;htt…

如何自学python

Python是一种高级编程语言,它具有简单易学、可读性强、可移植性好、功能丰富等优点,因此在许多领域都被广泛使用,如科学计算、数据分析、人工智能、Web开发、游戏开发等等。 Python具有丰富的标准库和第三方库,可以帮助程序员快速开发功能强大的应用程序。同时,Python也具…

免费下载全网视频系列:一键下载央视视频

之前分享过全网视频下载工具下载视频不求人&#xff0c;免费下载全网视频&#xff0c;今天再分享几个下载央视视频的工具。 第一个是央视频4k下载器&#xff0c;比如下载这个视频https://www.yangshipin.cn/#/video/home?vidv0000313oqb&#xff0c;打开工具在命令行输入 v00…

Vue.js+SpringBoot开发在线课程教学系统

目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2.3 课时管理模块2.4 课程交互模块2.5 系统基础模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示4.1 管理后台4.2 用户网页 五、样例代码5.1 新增课程类型5.2 网站登录5.3 课…

[技巧]Arcgis之图斑四至范围批量计算

ArcGIS图层&#xff08;点、线、面三类图形&#xff09;四至范围计算 例外一篇介绍&#xff1a;[技巧]Arcgis之图斑四至点批量计算 说明&#xff1a;如下图画出来的框&#xff08;范围标记不是很准&#xff09; &#xff0c;图斑的x最大和x最小&#xff0c;y最大&#xff0c;…

社区店经营实战策略:如何打造火爆生意并持续盈利?

在竞争激烈的商业环境中&#xff0c;经营一家成功的社区店需要一套全面而有效的策略。作为一名开鲜奶吧5年的创业者&#xff0c;我将分享一些关键的经营策略&#xff0c;帮助你打造火爆生意并实现持续盈利。 1、 市场调研&#xff1a; 在开店之前&#xff0c;深入了解你所在社…

内存占用构造方法

#使用虚拟内存构造内存消耗 mkdir /tmp/memory mount -t tmpfs -o size5G tmpfs /tmp/memory dd if/dev/zero of/tmp/memory/block #释放消耗的虚拟内存 rm -rf /tmp/memory/block umount /tmp/memory rmdir /tmp/memory #内存占用可直接在/dev/shm目录下写文件

#WEB前端(表单)

1.实验&#xff1a; form、input、label 登录界面&#xff0c;表单填写界面 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; 4.代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&q…

【Linux】基本指令(中)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) man指令 语法:man [选项] 命令 功能:Linux的命令有很多参数&#xff0c;我们无法全部记忆的话&#xff0c;就可以通过man指令查看联机手册获取帮助。…

递归与回溯2

一&#xff1a;递归分治 什么是递归&#xff1f; 函数自己调用自己通过函数体来进行循环以自相似的方法重复进行的过程 递归的过程&#xff1a;先自顶向下找到递归出口&#xff0c;在自底向上回到最初的递归位置 推导路径未知的题目只能用递归不能用循环 比如求多叉树的节点&…