
作者:敲代码の流川枫
博客主页:流川枫的博客
专栏:和我一起学java
语录:Stay hungry stay foolish
工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器——牛客网
文章目录
类实例化产生的对象之间可能存在某些关联,继承就是提取这些共性从而达到代码复用
概念:在保持原有类特性的基础上进行扩展,增加新功能,产生新的类的过程,这个类称派生类
继承主要解决的问题是:共性的抽取,实现代码复用
关键字:extends
格式:
- 修饰符 class 子类 extends 父类 {
-
- //...
-
- }
子类会继承父类的成员变量或者成员方法
子类继承父类后要添加自己特有的成员,即除了父类之外的特性
- class Animal{
- public String name;
- public int age;
-
- public void eat() {
- System.out.println(name+"吃饭");
- }
- }
- class Dog extends Animal{
- //新加的属性
- public String silly;
- public void houseGuard() {
- System.out.println("看门");
- }
- }
- class Cat extends Animal {
-
- //没有添加新属性
- public void catchMouse() {
- System.out.println(name+"抓老鼠");
- }
- }
- public class Test {
- public static void main(String[] args) {
-
- //name和age属性是从父类Animal中继承下来的
-
- Dog dog = new Dog();
- Cat cat = new Cat();
-
- }
- }
还要注意:Java中不支持多继承,一个子类只能继承一个父类
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找
如果找不到,则在父类继承下来的成员变量中寻找要访问的成员变量,找不到编译失败
成员方法名字不同:
优先访问自己的,若没有,去访问从父类继承的
成员方法名字相同:
父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,没有则报错
用法:在子类方法中访问父类的成员
- class Dog extends Animal{
-
- public String silly;
- public void houseGuard() {
-
- System.out.println(super.name+"看门");
-
- }
- }
父类的name没有赋初值,因此是null ,这样就访问到了同名的父类的成员变量

this.会有优先问自己的,没有则访问从父类中继承的
super.直接访问从父类中继承下来的,在子类方法中,如果想要明确访问父类中成员时,借助super关键字即可
总结:
super.data;访问父类的普通成员变量
super.func();访问父类的普通成员方法
super();访问父类的构造方法
注意:上文父类的普通成员方法、变量是指非静态成员方法、变量
子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法
看代码:
- class Animal{
- public String name;
- public int age;
-
- //提供一个两个该参数的构造方法
- public Animal(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public void eat() {
- System.out.println(name+"吃饭");
- }
- }
-
- //此处报错
- class Dog extends Animal{
-
- public String silly;
- public void houseGuard() {
- System.out.println(super.name+"看门");
- }
- }

对象的初始化需要调用构造方法
添加了带有两个参数的构造器后,编译器不会提供无参的构造方法,因此出现错误
接下来我们看当提供了两个参数的构造方法时如何初始化:
- class Dog extends Animal{
-
- public String silly;
- public Dog(String name, int age, String silly) {
-
- //先初始化父类部分
- super(name, age);
- this.silly = silly;
-
- }
-
- public void houseGuard() {
- System.out.println(super.name+"看门");
- }
- }
super(name,age)会先调用父类的构造方法完成初始化
this.silly = silly会完成自己属性的初始化
总结:
1. 父类显式定义无参或者默认的构造方法,子类构造方法第一行会默认有隐含的super()调用
2. 父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现
1. 修饰变量或字段,表示常量
2. 修饰类:表示此类不能被继承
String 字符串类, 就是用 final 修饰的, 不能被继承
3. 修饰方法:表示该方法不能被重写
与继承相似,组合也是表示类之间关系的方式,能实现代码的复用
继承表示各种类抽象出来的共性,对象之间是is-a的关系
组合(Composition)体现的是整体与部分、拥有的关系,即has-a的关系
例如交通工具车的组合:
- class Tire {
- public void run() {
- System.out.println("轮胎转动");
- }
- }
-
- class Light {
- public void light() {
- System.out.println("灯亮");
- }
- }
-
- public class Vehicle {
- private Tire tire;
- private Light light;
-
- public Vehicle(Tire tire,Light light) {
- this.tire = tire;
- this.light = light;
- }
-
- public void operation() {
- light.light();
- tire.run();
- }
-
- public static void main(String[] args) {
- Tire tire = new Tire();
- Light light = new Light();
- Vehicle vehicle = new Vehicle(tire,light);
- //灯亮
- //轮胎转动
- vehicle.operation();
- }
- }
不同的对象在完成某个行为时会产生出不同的状态就叫多态
例如:手机支付时产生的多态

1. 必须在继承体系下
2. 子类必须要对父类中方法进行重写
3. 通过父类的引用调用重写的方法
多态体现在:当代码运行时,传递不同类的对象时,会调用对应类中的方法
例如:
- class Animal{
- public String name;
- public int age;
-
- public Animal(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public void eat() {
- System.out.println(name+"吃饭");
- }
- }
-
- class Dog extends Animal{
-
- public String silly;
-
- public Dog(String name, int age, String silly) {
- super(name, age);
- this.silly = silly;
- }
- @Override
- public void eat() {
- System.out.println(name+"吃狗粮");
- }
-
- public void houseGuard() {
- System.out.println(super.name+"看门");
- }
- }
- class Cat extends Animal {
-
- public Cat(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void eat() {
- System.out.println(name+"吃猫粮");
- }
- //没有添加新属性
- public void catchMouse() {
- System.out.println(name+"抓老鼠");
- }
- }
- public class Test {
- public static void eat(Animal animal) {
-
- animal.eat;
-
- }
- public static void main(String[] args) {
- Dog dog = new Dog("dog",2,"silly");
- Cat cat = new Cat("cat",3);
- eat(dog);
- eat(cat);
-
- }
- }

Test类中的eat方法参数为Animal,该方法内部并不知道,也不关注当前的a引用指向哪个实例,此时 a这个引用调用 eat方法可能会有多种不同的表现(和 a 引用的实例相关), 这种行为就称为多态
概念:返回值和形参都不能改变,子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写
重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法
【方法重写的规则】
子类与父类方法原型一致:返回值类型 方法名 (参数列表) 要完全一致
被重写的方法返回值类型可以不同,但是必须是具有父子关系的
访问权限不能比父类中被重写的方法的访问权限更低,父类方法被public修饰,则子类中重写该方法就不能声明为 protected
父类被static、private修饰的方法、构造方法都不能被重写
@Override注解能帮我们进行一些合法性校验,重写没有构成时报错
- //语法格式:父类类型对象名 = new 子类类型()
-
- Animal animal = new Cat("cat",2);
-
使用:
方法一:直接赋值(子类对象赋值给父类对象)
- public class Test {
- public static void main(String[] args) {
- Dog dog = new Dog("dog",2,"silly");
- Animal animal = dog;
- Animal animal1 = dog;
- Animal animal2 = dog;
- }
- }
方法二:方法传参(形参为父类型引用,可以接收任意子类的对象)
- public static void eat(Animal animal) {
-
- animal.eat;
-
- }
方法三:方法返回(作返回值:返回任意子类对象)
- public static Animal func(){
- return new Cat("dog",2);
- }
优点:让代码实现更简单灵活
缺陷:不能调用到子类特有的方法
- public class Test {
- public static void main(String[] args) {
-
- Animal animal = new Cat("haha",2);
-
- if(animal instanceof Cat){
- Cat cat = (Cat) animal;
- cat.catchMouse();
- }
- }
- }
为了提高向下转型的安全性,引入了instanceof,如果该表达式为true,则可以安全转换
“ 本期的分享就到这里了, 记得给博主一个三连哈,你的支持是我创作的最大动力!
