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

JavaSE-继承

继承(inheritance)

继承的意义

我们首先来看下面两个类:

public class Dog {public String name;public int age;public void eat(){System.out.println(this.name+"正在吃饭");}public void bark(){System.out.println(this.name+"正在汪汪叫");}
}
public class Cat {public String name;public int age;public void eat(){System.out.println(this.name+"正在吃饭");}public void miao(){System.out.println(this.name+"正在喵喵叫");}
}

这两个名为Dog和Cat的类拥有相同的成员变量name、age以及相同的成员方法eat

在主方法中可以正常调用他们的变量和方法。

public class test {public static void main(String[] args) {Dog dog = new Dog();dog.name="大黄";dog.eat();dog.bark();System.out.println("============");Cat cat = new Cat();cat.name="大橘";cat.eat();cat.miao();}
}

 我们可以发现在Dog和Cat中就具有相同的成员,如果每次新建一个动物类时都要加入这些相同成员,未免有些麻烦,于是继承出现了。

如何继承

新建一个Animals类,将动物所具有的共同成员放入其中并删去原来类中的共同成员。

public class Animals {public String name;public int age;public void eat(){System.out.println(this.name+"正在吃饭");}
}

在原来的类名后加上extends Animals。

格式如下:

修饰符 class 子类名 extends 父类名{

public class Dog extends Animals{public void bark(){System.out.println(this.name+"正在汪汪叫");}
}
public class Cat extends Animals{public void miao(){System.out.println(this.name+"正在喵喵叫");}
}

这样原来的主函数依然可以正常运行。Animals就称为父类/基类/超类,Dog和Cat就叫做子类或者派生类。通过继承,我们实现了代码的复用。

继承中的访问与调用

子类访问父类成员变量

下面三段代码分别是子类,父类和主方法。

package demo2;public class Derived extends Base{public int c=3;public void func(){System.out.println(this.a);System.out.println(this.b);System.out.println(this.c);}
}
package demo2;public class Base {public int a=1;public int b=2;
}
package demo2;public class test {public static void main(String[] args) {Derived derived =new Derived();derived.func();}
}

运行结果:

 子类访问了继承自父类的a和b,并访问了自身的成员变量c。

在子类中加入a=100:

package demo2;public class Derived extends Base{public int c=3;public int a=100;public void func(){System.out.println(this.a);System.out.println(this.b);System.out.println(this.c);}
}

运行结果:

可见当父类和子类中同时出现变量a时,this关键字访问的是子类自身的a。

如何在子类中访问父类中的同名变量a?

使用super关键字。

package demo2;public class Derived extends Base{public int c=3;public int a=100;public void func(){System.out.println(super.a);System.out.println(this.b);System.out.println(this.c);}
}

运行结果:

 在子类方法中或者通过子类对象访问成员时:

1.如果访问的成员变量子类中有,优先访问自己的成员变量。

2.如果访问的成员变量子类中无,则访问父类继承下来的,如果父类中也无,则编译报错。

3.如果访问的成员变量与父类中的成员变量同名,则优先访问自己的。

子类访问父类成员方法

当子类中成员方法与父类中成员方法不同名时,可以直接在子类中调用父类成员方法:

public class Base {public int a=1;public int b=2;public void testBase(){System.out.println("testBase---");}
}
public class Derived extends Base{public int c=3;public int a=100;public void testDerived(){System.out.println("testDerived---");}public void test(){testBase();testDerived();}
}

public class test {public static void main(String[] args) {Derived derived =new Derived();derived.test();}
}

运行结果:

 当子类中方法与父类中方法重名时,优先就近原则调用子类自己的方法,同时可以构成方法的重载和方法的重写:

方法的重载:

public class Base {public int a=1;public int b=2;public void testA(){System.out.println("testA()---");}
}public class Derived extends Base{public int c=3;public int a=100;public void testA(char a){System.out.println("testA(char a)---");}public void test(){testA();testA('a');}
}public class test {public static void main(String[] args) {Derived derived =new Derived();derived.test();}
}

 并且可以使用super关键字调用父类方法:

public class Base {public int a=1;public int b=2;public void testA(){System.out.println("testA(Base)---");}
}public class Derived extends Base{public int c=3;public int a=100;public void testA(){System.out.println("testA(Derived)---");}public void test(){testA();super.testA();}
}public class test {public static void main(String[] args) {Derived derived =new Derived();derived.test();}
}

运行结果:

但是super只能指代父类,不能指代父类的父类玩套娃。

当子类继承父类之后,在不使用构造方法的情况下,java会自动为子类和父类提供构造方法,但当我们为类添加构造方法时,子类需要显式的调用父类的构造方法,帮助父类完成初始化。

public class Animals {public String name;public int age;public void eat(){System.out.println(this.name+"正在吃饭");}public Animals(String name,int age){this.name=name;this.age=age;}
}public class Dog extends Animals {public void bark(){System.out.println(this.name+"正在汪汪叫");}public Dog(String name,int age){super(name,age);}
}public class test {public static void main(String[] args) {Dog dog = new Dog("大黄",3);System.out.println("name:"+dog.name+" age:"+dog.age);}
}

简而言之,当为父类添加构造方法时,需要同时在子类中添加构造方法并在第一行使用super关键字帮助父类初始化。

super和this关键字

1.super()和this()构造方法只能在第一行使用,并且不能同时出现。 

2.在非静态成员方法中,this用来访问本类中的方法和属性,super用来访问继承父类中的方法和属性。

3.在构造方法中,this()用于调用本类构造方法,super()用于调用继承父类的构造方法,两种调用不能同时在构造方法中出现。

4.构造方法中一定会有super()的调用,即使用户没有写编译器也会添加,但this()用户不写则没有。

继承中的代码块运行顺序

猜测下列标号代码块的运行顺序:

public class Animals {public String name;public int age;static{System.out.println("static::Animal{}");}//1{System.out.println("实例化代码块 Animal");}//2public Animals(String name,int age){this.name=name;this.age=age;System.out.println("Animal()");}//3
}public class Cat extends Animals {static{System.out.println("static::Cat{}");}//4{System.out.println("实例化代码块 Cat{}");}//5public void miao(){System.out.println(this.name+"正在喵喵叫");}public Cat(String name,int age){super(name,age);System.out.println("Cat()");}//6
}public class test {public static void main(String[] args) {Cat cat=new Cat("大橘",4);}
}

运行结果:

运行顺序是:142356

从中可以得出代码块的运行逻辑:先执行父类,子类的静态代码块,再执行父类的实例化和初始化,再执行子类的实例化和初始化。

 继承的权限

private:仅允许本类中调用

default:允许同包中的不同类使用

protected:允许不同包中的子类使用

public:允许不同包的非子类中使用

在继承的权限使用中,我们要尽可能的做到封装:即最大的私密性,隐藏内部细节,只显露出必要的内容给使用者,能够使用private,就尽量不要使用public。有一个暴力的方法,就是将所有的变量设置为private权限,将所有的方法设置为public权限。

final关键字

继承关系不宜有太多层,一般三层为上限。final在java中对变量修饰可以将其变为不可改变的常量,对子类修饰则可以防止这个类被继承,当它被继承时编译器会报错,这个类就被称为密封类。

继承与组合

继承中子类与父类的关系可以表示为子类 is a 父类,而组合可以表示为前者 has a后者,或者后者 is a part of 前者,如汽车和轮胎的关系。

class Student{}class Teacher{}public class school {public Student[] student=new Student[10];public Teacher[] teacher=new Teacher[10];
}

学生和老师是学校的一部分,这就是组合关系。

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

相关文章:

  • UI前端与数字孪生结合实践案例:智慧零售的库存管理优化系统
  • 算法学习笔记:10.Prim 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 【Mac】实现Docker下载安装【正在逐步完善】
  • 【论文阅读】CogVideoX: Text-to-Video Diffusion Models with An Expert Transformer
  • 【计算机基础理论知识】C++篇(一)
  • 暑假读书笔记第四天
  • 【Python-GEE】如何利用Landsat时间序列影像通过调和回归方法提取农作物特征并进行分类
  • python transformers库笔记(BertForTokenClassification类)
  • 【牛客刷题】小红的与运算
  • node.js中yarn、npm、cnpm详解
  • 精益管理与数字化转型的融合:中小制造企业降本增效的双重引擎
  • 算法训练营DAY29 第八章 贪心算法 part02
  • 实战Linux进程状态观察:R、S、D、T、Z状态详解与实验模拟
  • 联通线路物理服务器选择的关键要点
  • No Hack No CTF 2025Web部分个人WP
  • Django双下划线查询
  • 微信小程序控制空调之接收MQTT消息
  • 如何利用AI大模型对已有创意进行评估,打造杀手级的广告创意
  • deepseek实战教程-第九篇开源模型智能体开发框架solon-ai
  • Python爬取知乎评论:多线程与异步爬虫的性能优化
  • React18+TypeScript状态管理最佳实践
  • Jenkins 使用宿主机的Docker
  • 深入解析 structuredClone API:现代JS深拷贝的终极方案
  • Ubuntu 版本号与别名对照表(部分精选)
  • Java使用接口AES进行加密+微信小程序接收解密
  • Linux Ubuntu系统下载
  • Docker企业级应用:从入门到生产环境最佳实践
  • any实现(基于LLVM中libcxx实现分析)
  • 深入理解Java虚拟机(JVM):从内存管理到性能优化
  • 基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架(1)搭建框架基本雏形