Extend继承

news2024/11/18 11:24:10

继承的作用

当我们定义了一个Person类:

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

现在,假设还需要定义一个Student类:

class Student{
    private Stirng name;
    private int age;
    private int score;

    public String getName(){....}
    public int getAge(){...}
    public int getScore(){...}

    public void setName(String name){...}
    public void setAge(int age){...}
    public void setScore(int score){...}
}

        通过观察我们发现这两个类相似,其中Student类包含了Person类中已有的字段和方法,只是多了一个score字段和相应的set、get方法。那能不能不用在Student类中写重复的代码呢?这时候我们就需要用继承(Extends)来解决这个问题。

        继承是面向对象编程中非常强大的一种机制,首先它可以实现代码的复用,当Student类继承Person类时,Student类就获得了Person的所有功能,我们只需要为Student类添加一些其他我们想实现的功能。在Java中我们用关键字extends来实现继承:

class Person{
    private Stirng name;
    private int age;
    public String getName(){....}
    public int getAge(){...}
    public void setName(String name){...}
    public void setAge(int age){...}
}
class Student extends Person{
    private int score;
    
    public int getScore(){...}
    public void setScore(int score){...} 
}

注意:子类自动获得父类的所有字段,严谨定义与父类重名的字段

        在我们定义Person的时候,没有写extends。在java中,没有明确写extend的类,编译器会自动加上extends Object。所以,任何类,除了Object,都会继承自某个类,如下图:

        java只允许一个类继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,他没有父类。

protected关键字

        继承有一个特点,就是子类无法继承父类的private字段或者private方法。例如,Student类无法访问Person类的name和age字段,这样,继承的作用就会被削弱。为了让子类可以访问父类的字段,我们需要把修饰符从private改为protected。用protected修饰的字段可以被父类访问

super关键字

        super关键字表示父类(超类),子类引用父类的字段时,可以用super.fieldName,例如:

public class Person {
	protected String name;
	private int age;

}
class Student extends Person{
	public String hello() {
	//子类允许访问父类protected修饰的成员变量和方法
	return "hello"+super.name;

	}
}

        实际上,这里使用super.name,或者this.name ,或者直接使用name的效果都是一样的。编译器会自动定位到父类的name字段。但是在某些时候,必须使用super:

public Main{
    public static void main(String[] args){
        Student s=new Student("Wei",18,100);
     }
}
class Person{
    protected String name;
    protected int age;
    
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}
class Student extends Person {
    protected int score;
    public Student(String name,int age,int score){
        this.score=score;
    }
}

        运行此代码,会得到一个编译错误,大意是在Student的构造方法中无法调用Person的构造方法。

        因为在Java中,任何子类的构造方法,第一句语句必须是调用父类的构造方法。如果没有明确的调用父类的构造方法,编译器会帮我们自动加一句super(),所以,Student的构造方法实际应该是这样的:

public Main{
    public static void main(String[] args){
        Student s=new Student("Wei",18,100);
     }
}
class Person{
    protected String name;
    protected int age;
    
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}
class Student extends Person {
    protected int score;
    public Student(String name,int age,int score){
        super();//自动调用无参构造方法
        this.score=score;
    }
}

        但是,在这个实例中,我们没有在父类中定义一个无参的构造方法,因此依然编译失败。解决方法是:手动调用Person类存在的某个构造方法,这样就可以正常编译了:

public Main{
    public static void main(String[] args){
        Student s=new Student("Wei",18,100);
     }
}
class Person{
    protected String name;
    protected int age;
    
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}
class Student extends Person {
    protected int score;
    public Student(String name,int age,int score){
        super(name,age);//手动调用有参构造方法
        this.score=score;
    }
}

        由此,我们可以得出结论:如果父类没有默认的构造方法,子类必须显式的通过super关键字,让编译器定位到某个合适的构造方法。

        这里还顺带引出了另一个问题:即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,而不是继承父类的。

简单应用

我们用一个有更完整功能的实例来加深一下对继承的理解:

//商品类(父类)
clas Product{
    //成员变量
    private double price;
    private int stock;
    //无参构造方法
    public Product(){
     }
    //有参构造方法
    public Product(double price,int stock){
        this.price=price;
        this.stock=stock;
    }
   //getter和Setter方法
	public double getPrice() {
		return price;
	}
	public void setPrice(double price){
        if(price<=0){
            this.price=0.01;
        }else{
            this.price = price;}
    }
    public int getStock() {
		return stock;
	}
	public void setStock(int stock) {
		this.stock = stock;
	}

}
//图书类(子类)
class Book extends Product{
    private String bookName;
	private String author;
    //构造方法
    public Book(String bookName,double price,String author,int 
                                                         stock)){
        this.bookName=bookName;
        this.author=author;
        super.setPrice(price);
        super.setStock(stock);
    }
    @Override
	public String toString() {
		return String.format("书名:《%s》,
                              作者:%s,价格:¥%f,
                              库存:%d",				
                              this.bookName,
                              this.author,super.getPrice(),
                              super.getStock());
	}
}

//手机类(子类)
class Phone extends Product{
	private int memory;
	private String model;
	public Phone(String model,int memory,double price,int stock) {                                                                                                                                                                                                                                                                                                                                 
    //方法一:通过父类的set和get方法,保存库存和价格
//  super.setPrice(price);
//  super.setStock(stock);

    //方法二:通过父类有参的构造方法,保存库存和价格
    super(price,stock){
    this.memory=memory;
    this.model=model;
    
}
    @Override
    public String toString() {
	    return String.format("型号:%s,价格:¥%f,内存:%dG,库存:%d"			            
                             this.model,super.getPrice(),
                             this.memory,super.getStock());
	}
}
public class Test {
	public static void main(String[] args) {
		Phone phone1=new Phone("Mate60",8888,128,67);
		Book book1=new Book("皮皮鲁和鲁西西",12.5,"李",80);
		System.out.println(book1);
		System.out.println(phone1);
	}

}

输出结果:

向上转型

        如果引用变量的类型是Student,它可以指向一个Student类型的实例:

Student s=new Student();

         如果引用变量的类型是Person,它可以指向一个Person类型的实例:

Person p=new Person();

        如果Student是从Person继承下来的,一个引用类型为Person的变量,它可以直接指向Student类型的实例:

Person p=new Student();

        因为Student继承自Person,因此,它拥有Person的全部功能。所以Person类型的变量,如果指向Student类型的实例,对他进行操作是没有问题的。这种把一个子类类型安全地变为父类类型的赋值,称为向上转型(upcasting)

        向上转型实际上是把一个子类安全地变为更抽象的父类类型,继承树的顺序是:Student->Person->Person->Object。所以可以把Student转换为Person类型,或者更高层次的Object。

Student s=new Student();
Person p=s;
Object o1=p;
Object o1=s;

向下转型

        和向上转型相反,如果把一个父类类型强制转换为子类类型,就是向下转型(downcasting)。例如:

Person p1=new Student();//向上转型
Person p2=new Person();
Student s1=(Student)p1;//ok
Student s2=(Student)p2;//runtime error! ClassCastException!

        运行时,Person类型实际上指向Student实例,p2指向Person实例,所以在进行向下转型时,p1转型为Student会成功,是因为p1本身指向Student实例p2转为Student会失败,是因为p2没有指向Student,而是指向Person,不能将父类变为子类,因为子类的方法可能比父类方法多,多的方法不能凭空变出来,因此向下转型会失败,会报ClassCastException异常。

        为了避免向下转型失败,Java提供了instanceof操作符,可以先判断这个实例是不是某种类型,再进行向下转型:

Person p=new Person();
System.out.println(instanceof Person);//true
System.out.println(instanceof Student);//false

Student s-new Student();
System.out.println(instanceof Student);//true
System.out.println(instanceof Person);//false

Person p=new Student();
if(p.instanceof Student){
    //只有判断成功才会向下转型
    Student s=(Student)p;//一定转型成功
}

综合应用

//父类
class Computer{
    private String cpu;//中央处理器
    private int ssd;//固态硬盘
    
    //无参构造方法
    public Compuetr(){
    }
    //有参构造方法
    public Compuetr(String cpu,int ssd){
        this.cpu=cpu;
        this.ssd=ssd;
    }
}
//子类:PC机
class PersonComputer extends Computer{
    private String displayCard;//显卡
    //构造方法
    public PersonComputer(String cpu,int ssd,String displayCard) {
        //手动调用父类的有参构造方法
        super(cpu,ssd);
        this.displayCard=displayCard;
    }
    public String getDisplayCard() {
		return displayCard;
	}
	public void setDisplayCard(String displayCard) {
		this.displayCard = displayCard;
	}
	
}
//子类:笔记本电脑
class NotebookComputer extends Computer{
	private String brand;//品牌
	public NotebookComputer(String cpu,int ssd,String brand) {
		//手动调用父类的有参构造方法
		super(cpu,ssd);
		this.brand=brand;
	}
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
	
}
public class Computer_test {
	public static void main(String[] args) {
		//对象数组
		//类型如果是父类,代表数组内可以保存任意一种子类的对象
        Computer[] array={
                          new Computer("Intel i8",127),
                          new PersonComputer("Intel i9",128,"8090Ti")
                          new NotebookComputer("AMD R9",512,"联想"),
			              new NotebookComputer("AMD R9",512,"小米"),
                          new PersonComputer("Intel i9",128,"4090T")
                          };
    for(int i=0;i<array.length;i++){
        //获取数组中的元素
        Computer comp=array[i];
        //向下转型
		//instanceof运算符:
        //判断当前引用comp指向的对象类型是否是PersonComputer
        if(comp instanceof PersonComputer){
            PersonComputer pc=(PersonComputer)cmp;
            System.out.println("台式机的显卡型号是:"
                                +pc.getDisplayCard());
        }else if(comp instanceof NotebookComputer){
            NotebookComputer nb=(NotebookComputer)comp;
            System.out.println("笔记本的品牌是:"+nb.getBrand());
        }
    }
}

输出结果:

台式机的显卡型号是:8090Ti
笔记本的品牌是:联想
笔记本的品牌是:小米
台式机的显卡型号是:4090Tipluse

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最小二乘法(带你 原理 实践)

文章目录 引言一、最小二乘法的基本原理二、最小二乘法的计算过程建立模型确定目标函数求解模型参数模型检验 三、最小二乘法的优缺点优点原理简单易懂统计特性优良适用范围广泛 缺点对异常值敏感假设条件较多 四、最小二乘法在实际应用中的案例五、如何克服最小二乘法的局限性…

OPCUA 学习笔记:程序模型

无论是边缘控制器&#xff0c;还是PLC 中&#xff0c;除了信息模型之外&#xff0c;还有应用程序&#xff0c;这些程序可能是IEC61131-3 编写的程序&#xff0c;也可能是其它程序开发的可执行程序。 尽管OPCUA 描述模型能力很强&#xff0c;但是它缺乏算法的描述方式。但是OPCU…

在k8s上部署dolphinscheduler

&#xff08;作者&#xff1a;陈玓玏&#xff09; 一、 前提条件 已部署k8s&#xff0c;版本信息如下&#xff1a; k8s为单机部署&#xff1b;已部署nfs&#xff0c;版本如下&#xff1b; 二、 部署helm 以下步骤安装的是二进制版本&#xff0c;如果通过脚本安装&#…

【AI视野·今日Sound 声学论文速览 第五十四期】Thu, 7 Mar 2024

AI视野今日CS.Sound 声学论文速览 Thu, 7 Mar 2024 Totally 8 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers Can Audio Reveal Music Performance Difficulty? Insights from the Piano Syllabus Dataset Authors Pedro Ramoneda, Minhee Lee, Dasa…

学生信息管理APP

设计内容简介 本次设计使用Android Studio实现一个学生信息管理系统,系统功能结构如下图所示: 详细设计 数据库设计SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低。…

Android14音频进阶:AudioTrack与AudioFlinger创建数据通道(五十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

UNIAPP微信小程序中使用Base64编解码原理分析和算法实现

为何要加上UNIAPP及微信小程序&#xff0c;可能是想让检索的翻围更广把。&#x1f607; Base64的JS原生编解码在uni的JS引擎中并不能直接使用&#xff0c;因此需要手写一个原生的Base64编解码器。正好项目中遇到此问题&#xff0c;需要通过URLLink进行小程序跳转并携带Base64参…

定时执行专家V7.1 多国语言版本英文版发布 - TimingExecutor V7.1 English Version Release

目录 ◆ About TimingExecutor ◆ Main Frame ◆ Job Dailog ◆ Trigger Dialog ◆ Setting Dialog ◆ About Dialog ◆ Job Detail Information panel ◆ Statistics Information panel ◆ About TimingExecutor 《定时执行专家》是一款制作精良、功能强大、毫秒精度…

数据库RDBMS1

配置MySQL 准备网络yum源&#xff08;准备物理机或一台虚拟机作为仓库服务器&#xff09; [rootzzgrhel8 ~]# yum install -y httpd php php-mysqlnd php-xml php-json createrepo [rootzzgrhel8 ~]# systemctl start httpd [rootzzgrhel8 ~]# systemctl enable httpd [root…

linux系统命令深入研究1——ls的参数

ls list命令有一些常用的参数&#xff0c;其中-a意为列出all全部文件&#xff08;包括隐藏文件&#xff09;&#xff0c;-l列出详细信息&#xff0c;-h以人类可阅读的方式列出文件大小 --full-time是列出详细时间信息&#xff0c;包括最后一次修改时间 -t是按时间排序&#xff…

【MySQL 系列】MySQL 起步篇

MySQL 是一个开放源代码的、免费的关系型数据库管理系统。在 Web 开发领域&#xff0c;MySQL 是最流行、使用最广泛的关系数据库。MySql 分为社区版和商业版&#xff0c;社区版完全免费&#xff0c;并且几乎能满足全部的使用场景。由于 MySQL 是开源的&#xff0c;我们还可以根…

Git 掌握

目录 一、前言 二、centos安装Git 三、Git基本操作 (1) 创建Git本地仓库 (2) 配置Git (3) 认识工作区&#xff0c;暂存区&#xff0c;版本库 四、添加文件 五、查看.git文件 六、修改文件 七、版本回退 八、撤销修改 (1) 场景一 对于还没有add的代码 (2) 场景二 已…

第一次捡垃圾

配置 cpu e3 1225 v6 淘宝 130 显卡 p106-100(1060矿卡的特称) 咸鱼 118 内存 8g 3200频率 2 咸鱼 702140 硬盘 128g 固态 咸鱼 35 主板 ex-b150m-v3 咸鱼 110 电源 400w 咸鱼 58 4热管cpu散热器 咸鱼 28 机箱 迷你 拼多多 28 电源线 1m5 淘宝 8 pcie转m.2 拼多多 9 编程器 用…

bun实现HTTP服务器

Bun 提供了原生 Bun.serve API。它实现了 fetch 以及Node.js的 http 和 https 模块。 这些模块已被重新实现&#xff0c;以使用 Bun 的快速内部 HTTP 基础设施。随意直接使用这些模块;像 Express 这样依赖于这些模块的框架应该开箱即用。有关详细的兼容性信息&#xff0c;请参阅…

R语言,实现MACD指标计算:股票技术分析的利器系列(1)

R语言&#xff0c;实现MACD指标计算&#xff1a;股票技术分析的利器系列&#xff08;1&#xff09; MACD指标代码完整代码介绍代码EMA函数calculate_DEA 函数calculate_MACD 函数 运行结果 MACD指标 先看看官方介绍&#xff1a; MACD (平滑异同平均线&#xff09; 指标说明 DI…

【leetcode热题】环形链表

难度&#xff1a; 简单通过率&#xff1a; 34.9%题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个链表&#xff0c;判断链表中是否有环。 为了表示给定链表中的环&#xff0c;我们使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;索…

图像处理与视觉感知---期末复习重点(2)

文章目录 一、空间域图像增强1.1 图像增强1.2 几种变换 二、直方图2.1 直方图定义2.2 直方图均衡化2.3 离散情况2.4 例子2.5 直方图匹配2.6 例子2.7 一道例题 三、空间滤波器3.1 定义3.2 例子 四、平滑空间滤波器4.1 作用与分类4.2 线性滤波器 五、统计排序滤波器5.1 定义与分类…

Qt添加VTK并绘制图形

文章目录 准备环境使用VS创建Qt Widget项目配置VTK依赖调试C/C链接器 添加vtk窗口测试代码 参考链接&#xff1a; VS2017配置QT环境(详细版)_vs2017 qt-CSDN博客 QT5VTK9.1最新配置方法_qt vtk-CSDN博客 VTK笔记-Qt5.12.11编译VTK9.0.3-QVTKOpenGLNativeWidget-CSDN博客 准…

算法---双指针练习-2(复写零)

1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 首先&#xff0c;通过遍历数组 arr 来确定复写后数组的最后一个元素的值下标 dest。这个下标表示在复写后的数组中&#xff0c;最后一个元素应该存储的位置。遍历过程中&#xff0c;如果遇到非零元素&#xff0c;则 de…