HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
随笔
关于作者
  • 《PureJavaCoderRoad》

    • 导读

    • Java基础

      • Java入门

      • Java语法

      • Java流程控制

      • 面向对象

        • 1、方法
        • 2、静态字段和静态方法
        • 3、继承
        • 4、重载和重写
        • 5、多态
        • 6、抽象类
        • 7、接口
        • 8、值传递和引用传递
        • 9、枚举
        • Head-Java对象的理解
      • 异常处理

    • Java进阶

    • Java高阶

    • 开发辅助工具

    • 计算机网络

    • 数据库

    • JavaEE

    • 中间件

    • 架构

    • 建议

  • PureJavaCoderRoad
  • Java基础
  • 面向对象
#继承
码农阿雨
2022-05-26
目录

3、继承

Java使用extends关键字来实现继承。

继承是Java的三大特性之一。

体现了类与类之间的“is-a”关系,当两个类存在相同的字段、功能方法,就可以使用继承的思想去编写代码。

# 继承

继承的语法:

class 父类 {
}
 
class 子类 extends 父类 {
}

eg:

public class Car {
    private String carName;
    private int carAge;
    public void dirve(){
    }    
}

class WuLingHongGuang extends Car {
    String ChineseName;
    @Override
    public void dirve(){  //重写父类方法
        //TODO
    } 
    .... //可以自定义扩展方法
}

class BaoMa extends Car{
    String EnglishName;
}

子类自动获得了父类的所有非private的字段、方法,严禁定义与父类重名的字段

在继承中,子类定义了一个与父类一模一样的方法,称为重写(Override),通常加上 @Override 注解表示

在OOP的术语中,

我们把Car称为超类(super class),父类(parent class),基类(base class)

把WuLingHongGuang、BaoMa 称为子类(subclass),扩展类(extended class)

# 继承树:

           ┌───────────┐
           │  Object   │
           └───────────┘
                 ▲
                 │
           ┌───────────┐
           │  	Car    │
           └───────────┘
              ▲      ▲
              │      │
              │      │
┌─────────────────┐ ┌─────────┐
│ WuLingHongGuang │ │  BaoMa  │
└─────────────────┘ └─────────┘

万物皆对象,在Java中,所有类的父类都是Object,没有明确写extends的类,编译器会自动加上extends Object。

# Object方法的API

Object是顶级父类,Object 类也是 Java 中唯一的一个没有父类的类。

任何一个类都将 Object 作为父类,也就意味着任何一个对象都可以赋值给 Object 对象。

Object类的API是必须要掌握的:

# 继承的特点

  • 子类拥有父类非 private 的属性、方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • Java 的继承是单继承(一次只能继承一个类),但是可以多重继承(A extends B;B extends C)

  • 子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。

# super 关键字

在重载中,this表示的是本实例。一般使用的例子是 this.name = name

在继承中,我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

子类的构造方法可以通过super()调用父类的构造方法。

👼如果父类没有默认的构造方法,子类就必须显式调用super()

eg:

public class Car {
    private String carName;
    private int carAge;
    Car(String carName,int carAge){
        this.carName=carName;
        this.carAge=carAge;
    }
}

class WuLingHongGuang extends Car {
    String ChineseName;
    
    WuLingHongGuang(String carName, int carAge) {
        super(carName, carAge);  //必须使用super显式调用父类的构造函数,且必须在构造函数第一行
        // TODO
    }
}

大概是因为构造函数是没办法继承,所以需要调用父类构造函数实例化父类

# 向上转型和向下转型

# 向上转型

一般要获得对象的引用,只需要new 即可:

Car car = new Car(); 
WuLingHongGuang wuLingHongGuang = new WuLingHongGuang();

以上两种都是正常引用类型,但是WuLingHongGuang类是继承Car 类的,那么,一个引用类型为Car的变量,能否指向WuLingHongGuang类型的实例?

答案是可以的。

eg:

Car wuLingHongGuangCar = new WuLingHongGuang();

Car wuLingHongGuangCar 表示父类的引用类型,

= new WuLingHongGuang() 表示指向子类对象。

合起来就叫做 父类的引用指向子类对象,被称为向上转型(upcasting)

相当于把一个子类类型安全地变为父类类型的赋值

WuLingHongGuang w = new WuLingHongGuang();
Car c = w ; // upcasting, ok
Object o1 = w; // upcasting, ok
Object o2 = c; // upcasting, ok

父类的引用指向子类对象,调用父类、子类都有的方法,调用的是子类的方法,但是如果父类没有该方法,仅仅子类有,则会编译报错:

public class Car {
    private String carName;
    private int carAge;

    void drive() {
        System.out.println("开车");
    }
}

class WuLingHongGuang extends Car {
    String ChineseName;
    @Override
    void drive() {
        System.out.println("开五菱宏光");
    }
}

class Test {
    public static void main(String[] args) {
        Car wuLingHongGuangCar = new WuLingHongGuang();
        wuLingHongGuangCar.drive();
    }
}

输出:

开五菱宏光

子类重写(覆盖)父类方法,调用的是子类方法

如果子类没有该方法,则调用父类方法

❗🚫 如果父类注释了 drive() 方法,则发生报错。wuLingHongGuangCar.drive();在编译的时候,wuLingHongGuangCar是指向父类Car的,所以父类必须有这个方法。

# 向下转型

把一个父类类型强制转型为子类类型,就是向下转型(downcasting)

eg:

Car wuLingHongGuangCar = new WuLingHongGuang();
Car car = new Car();

WuLingHongGuang w1 = (WuLingHongGuang) wuLingHongGuangCar; //downcasting
WuLingHongGuang w2 = (WuLingHongGuang) car; //父类转为子类 报错 java.lang.ClassCastException

但并不是所有类都可以向下转型的。

不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。

使用instanceof 关键字则可以判断两者关系,instanceof实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为null,那么对任何instanceof的判断都为false。

利用instanceof,在向下转型前可以先判断:

Car wuLingHongGuangCar = new WuLingHongGuang();
Car car = new Car();

if (wuLingHongGuangCar instanceof WuLingHongGuang){ //true
    WuLingHongGuang w1 = (WuLingHongGuang) wuLingHongGuangCar; //downcasting
}
if (car instanceof WuLingHongGuang){ //false
    WuLingHongGuang w2 = (WuLingHongGuang) car; //报错
}

# 阻止继承

父类如果不希望自己的方法或者字段被继承,可以使用 final 或者 private 修饰符

# final关键字

只要某个class没有final修饰符,那么任何类都可以从该class继承。

如果类加了final修饰,则该类不能被继承。

eg:

public final class Car {
    private String carName;
    private int carAge;
    public void drive(){
    }
}
class WuLingHongGuang extends Car {
    String ChineseName;
}

# static关键字

声明为 static 的方法不能被重写,但是能够被再次声明。

# private 修饰符

子类拥有父类非 private 的属性、方法。

父类使用了private修饰变量、方法,则表示该变量、方法不能被继承,无法被子类访问。

protected允许子类访问父类的字段和方法

eg:

public class Car {
    private String carName;
    private int carAge;
    void drive() {
    }
    private void printCar() {
        System.out.println("Car");
    }
}

class WuLingHongGuang extends Car {
    String ChineseName;
}

class Test {
    public static void main(String[] args) {
        WuLingHongGuang wuLingHongGuang = new WuLingHongGuang();
        wuLingHongGuang.drive();
        wuLingHongGuang.printCar(); //报错   父类的printCar 方法是  private
    }
}

# 继承与组合的关系

is-a 的关系才能算得上是继承,不能说有共同一个参数就要套上继承关系。

如:

HaC 类,也有 ChineseName变量,但是写成 extends WuLingHongGuang就很奇怪

这种应该属于组合关系

class HaC {
    String ChineseName;
    int age;
    WuLingHongGuang wuLingHongGuang;
}

准确的说 继承是is-a关系,组合是has关系。

不过我真的没有五菱宏光~

# 初始化顺序

子类继承父类,因为构造函数是不能继承的,那子类、父类的初始化顺序是怎么样的呢?

eg:

public class Car {
    Car(){
        System.out.println("父类:开车");
    }
}

class WuLingHongGuang extends Car{
    WuLingHongGuang(){
        System.out.println("子类:开五菱宏光");
    }
}

class Test{
    public static void main(String[] args) {
        WuLingHongGuang wuLingHongGuang = new WuLingHongGuang();
    }
}

输出:

父类:开车
子类:开五菱宏光

可以看到,继承关系是先初始化父类,先执行父类的构造方法,再执行子类的构造方法。

拓展:

# Java中父类怎么调用子类的方法?

eg:

class A{
    A(){
        print();
    }
    void print(){
        System.out.println("A");
    }
}
class B extends A{
    @Override
    void print(){
        System.out.println("B");
    }
}
class MyTest{
    public static void main(String[] args) {
        new B();
    }
}

输出:

B

父类确实能调用子类的方法,但是没有必要,如果要调用子类,就没必要继承这个父类了。

如果要调用子类方法,参考:https://www.jb51.net/article/159636.htm

阅读全文
×

(为防止恶意爬虫)
扫码或搜索:HelloCoder
发送:290992
即可永久解锁本站全部文章

解锁
#继承
上次更新: 2025-02-21 06:04:57
最近更新
01
《LeetCode 101》
02-21
02
IDEA、Golang、Pycharm破解安装
02-21
03
《LeetCode CookBook》
02-21
更多文章>
Theme by Vdoing | Copyright © 2020-2025 码农阿雨
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式