Java 继承(extends)详解

Java 继承(extends)详解一、继承问题的引出继承性是面向对象的第二大主要特征。下面首先编写两个程序:Person类、Student类。Person类:classPerson{privateStringname;privateintage;publicvoidsetName(Stringname){

大家好,又见面了,我是你们的朋友全栈君。

一、继承问题的引出

继承性是面向对象的第二大主要特征。
下面首先编写两个程序:Person类、Student类。

Person类:

class Person {
         private String name ;
         private int age ;
         public void setName(String name) {
                   this.name = name ;
         }
         public void setAge(int age) {
                   this.age = age ;
         }
         public String getName() {
                   return this.name ;
         }
         public int getAge(){
                   return this.age ;
         }
}

Student类:

class Student {
         private String name ;
         private int age ;
         private String school ;
         public void setName(String name) {
                   this.name = name ;
         }
         public void setAge(int age) {
                   this.age = age ;
         }
         public void setSchool(String school) {
                   this.school = school ;
         }
         public String getName() {
                   return this.name ;
         }
         public int getAge(){
                   return this.age ;
         }
         public String getSchool() {
                   return this.school ;
         }
}

以上两个程序通过代码的比较可以清楚的发现:代码之中存在了重复,而按照之前所学,这种重复是不可能消除的。

在所有的代码之中,最具有重复意义的就是链表类,针对于每一个简单Java类或者是说其他的任何类,都编写一个链表程序,代码量庞大,而且不方便维护。

二、继承的概念

继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

在Java之中,如果要实现继承的关系,可以使用如下的语法:

class 子类 extends 父类 { 
   }

子类又被称为派生类; 父类又被称为超类(Super Class)。

观察继承的基本实现:

package com.wz.extendsdemo;

class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

class Student extends Person { // Student类继承了Person类
}

public class TestDemo {
    public static void main(String args[]) {
        Student stu = new Student(); // 实例化的是子类
        stu.setName("张三"); // Person类定义
        stu.setAge(20); // Person类定义
        System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge());
    }
}

运行结果:

姓名:张三,年龄:20

通过代码可以发现,子类(Student)并没有定义任何的操作,而在主类中所使用的全部操作都是由Person类定义的,这证明:子类即使不扩充父类,也能维持父类的操作。

在子类之中扩充父类的功能:

package com.wz.extendsdemo;

class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

class Student extends Person { // Student类继承了Person类
    private String school; // 子类的属性

    public void setSchool(String school) {
        this.school = school;
    }

    public String getSchool() {
        return this.school;
    }
}

public class TestDemo {
    public static void main(String args[]) {
        Student stu = new Student(); // 实例化的是子类
        stu.setName("张三"); // Person类定义
        stu.setAge(20); // Person类定义
        stu.setSchool("清华大学"); // Student类扩充方法
        System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool());
    }
}

运行结果:

姓名:张三,年龄:20,学校:清华大学

以上的代码,子类对于父类的功能进行了扩充(扩充了一个属性和两个方法)。但是思考一下:子类从外表看是扩充了父类的功能,但是对于以上的代码,子类还有一个特点:子类实际上是将父类定义的更加的具体化的一种手段。父类表示的范围大,而子类表示的范围小

三、继承的限制

虽然继承可以进行类功能的扩充,但是其在定义的时候也是会存在若干种限制的。

限制一:一个子类只能够继承一个父类,存在单继承局限。
错误的写法:

class A { 
   }
class B { 
   }
class C extends A,B { 
   }          // 一个子类继承了两个父类

以上操作称为多重继承,实际上以上的做法就是希望一个子类,可以同时继承多个类的功能,但是以上的语法不支持而已,但是可以换种方式完成同样的操作。

正确的写法:

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

C实际上是属于(孙)子类,这样一来就相当于B类继承了A类的全部方法,而C类又继承了A和B类的方法,这种操作称为多层继承。

结论:Java之中只允许多层继承,不允许多重继承,Java存在单继承局限。

限制二:在一个子类继承的时候,实际上会继承父类之中的所有操作(属性、方法),但是需要注意的是,对于所有的非私有(no private)操作属于显式继承(可以直接利用对象操作),而所有的私有操作属于隐式继承(间接完成)。

package com.wz.extendsdemo;

class A { 
   
    private String msg;

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return this.msg;
    }
}

class B extends A { 
   
    public void print() {
        //System.out.println(msg); // 错误: msg定义为private,不可见
    }
}

public class TestDemo { 
   
    public static void main(String args[]) {
        B b = new B();
        b.setMsg("张三");
        System.out.println(b.getMsg());
    }
}

此时对于A类之中的msg这个私有属性发现无法直接进行访问,但是却发现可以通过setter、getter方法间接的进行操作。

限制三:在继承关系之中,如果要实例化子类对象,会默认先调用父类构造,为父类之中的属性初始化,之后再调用子类构造,为子类之中的属性初始化,即:默认情况下,子类会找到父类之中的无参构造方法。

package com.wz.extendsdemo;

class A { 
   
    public A() {         // 父类无参构造
              System.out.println("*************************") ;
    }
}
class B extends A { 
   
    public B() {         // 子类构造
              System.out.println("#########################");
    }
}
public class TestDemo { 
   
    public static void main(String args[]) {
              B b = new B() ;   // 实例化子类对象
    }
}

运行结果:

*************************
#########################

这个时候虽然实例化的是子类对象,但是发现它会默认先执行父类构造,调用父类构造的方法体执行,而后再实例化子类对象,调用子类的构造方法。而这个时候,对于子类的构造而言,就相当于隐含了一个super()的形式:

class B extends A { 
   
    public B() { // 子类构造
        super(); // 调用父类构造
        System.out.println("#########################");
    }
}

现在默认调用的是无参构造,而如果这个时候父类没有无参构造,则子类必须通过super()调用指定参数的构造方法:

package com.wz.extendsdemo;

class A { 
   
    public A(String msg) { // 父类构造
        System.out.println("*************************");
    }
}

class B extends A { 
   
    public B() { // 子类构造
        super("Hello"); // 调用父类构造
        System.out.println("#########################");
    }
}

public class TestDemo { 
   
    public static void main(String args[]) {
        B b = new B(); // 实例化子类对象
    }
}

运行结果:

*************************
#########################

在任何的情况下,子类都逃不出父类构造的调用,很明显,super调用父类构造,这个语法和this()很相似:super调用父类构造时,一定要放在构造方法的首行上。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/156704.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • hadoop技术论坛日志分析—mapredu最后一步_睿派克技术论坛

    hadoop技术论坛日志分析—mapredu最后一步_睿派克技术论坛http://bbs.hadoopor.comhttp://www.hadoopor.comhttp://forum.hadoopor.comhttp://hadoop.hadoopor.comhtt

  • elf文件解析器_elf文件下载

    elf文件解析器_elf文件下载前两天网上投递了简历,面试了一家C++公司,然后对面负责人给我发了一份笔试题,题目是:请写出一个ELF文件解析器,需要能打印出所有segments和sections,并列出每个section和segment的映射关系。首先了解elf是什么,它的结构是怎么样的,然后去读一下别人的源码,读懂之后,自己开始编码。源码如下(”elf.h”头文件见后文),它会报warning,但是貌似不太影…

    2022年10月29日
  • RapidXML问题

    RapidXML问题XML在编程中会经常应用RapidXML就是用C++实现的一种XML工具它是开源、灵活且高效的仅仅由4个头文件组成,可以直接编译到项目当中。rapidxml.hpprapidxml_utils.hpprapidxml_print.hpprapidxml_iterators.hpp在Linux或者Qt等环境想使用rapidxml_print.hpp中的类会有声明的问题,所以可以在文件的104行处插入如下代码template<classOutIt,classCh>inli

  • o蓝屏之死—stop:0X000000c5(0x000000c4等系列)—Mr.Zhang「建议收藏」

    o蓝屏之死—stop:0X000000c5(0x000000c4等系列)—Mr.Zhang「建议收藏」相信大家今天所用的系统大多是盗版的windows系列,但万幸的是我们勤劳的中华民族是一个智慧的民族!即使创造不出好的操作系统也会将盗版进行到底,最终形成自己的盗版文化!!!有幸成为一名中华民族的一份子,可以畅享盗版文化!!!       前天帮人运行数据,期间卡了几次,帮人查资料的时候顺便用了下代理。结果第二天早上开机之后,几分钟内就成了如下图所示:        相信大家很久

  • python微信机器人制作教程+源码[通俗易懂]

    python微信机器人制作教程+源码[通俗易懂]python微信机器人,定时机器人,监控机器人。

  • 修改计算机用户名 未识别网络,电脑出现未识别的网络,无Internet访问解决办法 这几步你要了解…[通俗易懂]

    修改计算机用户名 未识别网络,电脑出现未识别的网络,无Internet访问解决办法 这几步你要了解…[通俗易懂]网卡驱动问题01在桌面的计算机图标上右键单击一下,选择【设备管理器】,然后在设备管理器页面下方找到【网络适配器】。02打开网络适配器列表,找到当前的网卡驱动,用鼠标右键点击一下,在弹出的菜单中选择【禁用】,接着再点击【启用】。好了,以上就是大致内容了,(END)更改适配器设置01在电脑桌面上找到网络图标,右键点击一下,在菜单中选择【属性】,然后会进入到网络属性的主界面。02接着,在属性界面的左侧菜…

    2022年10月14日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号