JAVA继承和多态详细讲解

本文详细介绍了Java中的继承和多态概念。继承允许子类从父类继承属性和方法,实现代码复用,同时介绍了super关键字在访问父类构造方法、成员变量和方法中的应用。多态则允许父类引用指向子类对象,使得代码更具抽象性和灵活性,提高程序的扩展性和可维护性。此外,文章还讨论了方法重写、final关键字以及Object类的常用方法,如equals()、getClass()和toString()。通过对这些概念的理解和运用,开发者可以更好地利用Java的面向对象特性进行编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象编程的重要知识:继承和多态。通过类的继承机制,可以使用已有的类为基础派生出新类,无需编写重复的程序代码,很好地实现程序代码复用。多态是面向对象编程中继封装和继承之后的另一大特征,它具体是指同一个行为具有多个不同表现形式或形态的能力。使用多态机制,可以提高程序的抽象程度和简洁性,最大程度地降低类和程序模块间的耦合性,并提高程序的可扩展性和可维护性。从Java语言的底层逻辑上看,封装和继承是为实现多态做准备的。

6.1 类的继承

继承描述了类的所属关系,多个类通过继承可形成一个关系体系,进而在原有类的基础上派生出新的类,扩展新的功能,从而实现了代码的复用。采用继承机制来设计软件系统中的类,可以提高程序的抽象程度,降低程序维护工作量,提高开发效率。

6.1.1 继承的概念

在现实生活中,“继承”是指一个对象直接使用另一对象的属性和方法,也可以指按照法律或遵照遗嘱接受死者的财产、职务、头衔、地位等。我们先利用现实生活中的例子来说明继承的含义。如图6.1所示,卡车(Truck类)和公交车(Bus类)都属于汽车(Car类),它们都有发动机(engine)和轮子(wheel),都可以行驶(run)和刹车(stop),但是卡车类新增了载重量(capacity)、拉货(load)和卸货(unload)方法,公共车类新增了载客量(capacity)、报站(busstop)和停靠(dock)方法。

在面向对象程序设计中,一个新类从已经存在的类中获得成员变量或成员方法,这种现象称为继承。提供继承信息的类被称为父类(超类、基类),得到继承信息的类被称为子类(派生类)。一个父类可以同时拥有多个子类,但Java语言不支持多重继承,所以一个类只能有一个父类。父类是所有子类的公共成员变量和成员方法的集合,而子类是父类的特例,子类继承父类的成员变量和成员方法,可以修改父类的成员变量或重写父类的方法,也可以增加新的成员变量或成员方法。采用继承机制来设计系统中的类,可以提高程序的抽象程度,更加接近于人类的思维方式。

继承机制的显著特点之一是可以实现代码复用。以第5章的Dog类为例,我们能够以它为样板而设计新的Cat类,代码如下:

1​ public class Cat {

2​  private String name;

3​  private int age;

4​  public void show(){

5​  System.out.println("猫咪"+name+"在吃咸鱼");

6​  }

7​ }

仔细观察这段代码我们会发现,在Dog类和Cat类中有很多重复代码, 假设我们后续增加Pig类、Monkey类等类,重复代码还不断增加。这时候,我们就可以提取这些类的相同的成员变量和成员方法,设计一个Anima(动物类),使Dog类、Cat类等继承Animal类。

6.1.2 继承的使用

在Java语言中,类的继承通过extends关键字来实现,在定义类时通过extends关键字指出新定义类的父类,表示在两个类之间建立了继承关系。新定义的类称为子类,它可以从父类那里继承所有非private(私有)的成员。Java继承的语法格式如下:

class 子类A extends 父类B{

// 代码块

}

该语法表示子类A派生于父类B,如果类B又是某个类的子类,则类A同时也是该类的间接子类。如果没有extends关键字,则该类默认为java.lang.Object类的子类。Java语言中的所有类都是直接或间接地继承java.langObject类得到的,所以之前所有例子中的类均是java.lang.Object类的子类。

接下来,通过案例来演示如何通过继承Animal类来派生Dog类、Cat类,从而形成类的继承体现,实现代码复用,如例6-1所示。

例6-1 Demo0601.java

1​ package com.aaa.p0601; // 需要先建立包

2​ 

3​ class Animal { // 定义父类Animal类

4​  public String name;

5​  public int age;

6​  public void show() {

7​  System.out.println("名字是" + name + ",年龄:" + age);

8​  }

9​ }

10​ class Dog extends Animal { // 定义子类Dog类

11​  String color;

12​  public void eat(){

13​  System.out.println(color + "色的狗狗在啃骨头");

14​  }

15​ }

16​ class Cat extends Animal{ // 定义子类Cat类

17​ }

18​ public class Demo0601{

19​  public static void main(String[] args) {

20​  Dog d = new Dog();

21​  d.name = "旺财";

22​  d.age = 3;

23​  d.color = "黑色";

24​  d.show();

25​  d.eat();

26​  }

27​ }

程序的运行结果如下:

名字是旺财,年龄:3

黑色的狗狗在啃骨头

例6-1中,Dog类通过extends关键字继承了Animal类,它就是Animal的子类,Cat类同样如此。从程序运行结果中可发现,Dog类虽然没有定义name、age成员变量和show()成员方法,但却能访问这些成员,说明子类可以继承父类所有的成员。

编程技巧: 使用继承时,先定义父类(超类、基类),再定义子类(派生类),很好地体现了面向对象的思想。

6.2 方法重写

在继承机制中,当父类中的方法无法满足子类需求或子类具有特有的功能的时候,就需要在子类中重写父类的方法(也称为方法覆盖)。准确地说,方法重写建立在继承关系之上,具体是指子类从父类中继承方法时,如果在子类中有定义名称、参数个数、参数类型均与父类中的方法完全一致,但方法内容不同,即子类修改了父类中方法的实现,此时创建的子类对象调用这个方法时,程序会调用子类的方法来执行,即子类的方法重写了从父类继承过来的同名方法。

当子类重写父类方法的时候,可以使用与父类相同的方法名及参数列表,也可以执行不同的功能。子类既可以隐藏和访问父类的方法,也可以覆盖继承父类的方法,体现了Java语言的优越性和灵活性。

接下来,通过案例来演示方法重写。以Animal为父类,Dog类、Cat类继承Animal类,Dog类重写了父类的show()方法,如例6-2所示。

例6-2 Demo0602.java

1​ package com.aaa.p0602;

2​ 

3​ class Animal { // 定义父类Animal类

4​  public String name;

5​  public int age;

6​  public Animal(){

7​  System.out.println("调用了动物类的构造方法Animal()");

8​  }

9​  public void show() {

10​  System.out.println("父类名字是" + name + ",年龄:" + age);

11​  }

12​ }

13​ class Dog extends Animal { // 定义子类Dog类

14​  String color;

15​  public Dog(){

16​  System.out.println("调用了狗类的构造方法Dog()");

17​  }

18​  public void eat(){

19​  System.out.println(color + "色的狗狗在啃骨头");

20​  }

21​  public void show() {

22​  System.out.println("狗狗名字是" + name + ",颜色是" + color);

23​  }

24​ }

25​ class Cat extends Animal { // 定义子类Cat类

26​ }

27​ public class Demo0602{

28​  public static void main(String[] args) {

29​  Dog d = new Dog();

30​  d.name = "旺财";

31​  d.age = 2;

32​  d.color = "黑色";

33​  d.show();

34​  d.eat();

35​  Cat c = new Cat();

36​  c.show();

37​  }

38​ }

程序的运行结果如下:

调用了动物类的构造方法Animal()

调用了狗类的构造方法Dog()

名字是旺财,颜色是黑色

黑色色的狗狗在啃骨头

调用了动物类的构造方法Animal()

父类名字是null,年龄:0

例6-2中,Dog类继承了Animal类的show()方法,但在子类Dog中对父类的show()进行了重写,Cat类只是继承了Animal类。从程序运行结果中可发现,第29行代码直接调用Dog()构造方法,理应输出“调用了狗类的构造方法Dog()”,但是先输出“调用了动物类的构造方法Animal()”,这是因为在执行子类的构造方法前,会首先调用父类中无参的构造方法,其目的是为了继承自父类的成员进行初始化操作。 第33行代码在调用Dog类对象的show()方法时,只会调用子类重写的方法,并不会调用父类的show()方法。Cat类中没有重写父类的show()方法,第36行代码中的Cat类对象仍然调用的是父类的show()方法,同时由于没有给Cat类对象的成员变量name和age赋值,所以显示的名字是默认值“null”,年龄也是默认值“

### Java 抽象类、继承多态的概念及用法 #### 1. 抽象类 抽象类是一种不能被实例化的特殊类,主要用于定义一组通用的行为或属性。它允许开发者声明一些方法而不需要提供具体的实现细节,强制子类去完成这些未实现的部分。 - **关键字**: 使用 `abstract` 关键字修饰的类称为抽象类。 - **特点**: - 抽象类可以包含抽象方法(只有声明没有实现)以及非抽象方法(有具体实现)[^1]。 - 子类必须实现所有抽象方法才能成为一个非抽象类;否则,子类也需要声明为抽象类。 ```java // 定义一个抽象类 public abstract class Animal { protected String name; public Animal(String name) { this.name = name; } // 抽象方法 public abstract void eat(); // 非抽象方法 public void sleep() { System.out.println(name + " is sleeping."); } } // 实现抽象类的子类 public class Dog extends Animal { public Dog(String name) { super(name); } @Override public void eat() { System.out.println(this.name + " is eating dog food."); } } ``` 在此例子中,`Animal` 是一个抽象类,其中包含了抽象方法 `eat()` 非抽象方法 `sleep()`。`Dog` 类实现了这个抽象类,并提供了 `eat()` 方法的具体实现[^1]。 --- #### 2. 继承 继承是面向对象编程的核心概念之一,表示一种“is-a”的关系。通过继承机制,子类可以从父类那里获得已有的属性行为,从而减少重复代码量并提高可维护性。 - **关键字**: 使用 `extends` 进行继承。 - **优点**: - 提高代码复用率。 - 易于扩展已有功能。 ```java class Parent { public void showParentMessage() { System.out.println("This message comes from the parent class."); } } class Child extends Parent { public void showMessageFromChild() { System.out.println("And here's one coming directly from child!"); } } public class TestInheritance { public static void main(String[] args) { Child c = new Child(); c.showParentMessage(); // 调用了来自父类的方法 c.showMessageFromChild(); // 调用了自己定义的新方法 } } ``` 在这个简单的示例里,`Child` 类继承了 `Parent` 类的所有公共成员函数,同时还增加了自己的独特功能[^2]。 --- #### 3. 多态 多态指的是同一种操作作用于不同的对象上会产生不同效果的现象。Java 支持两种主要形式的多态——静态多态(即方法重载)与动态多态(即方法覆盖/重写)。后者尤其重要,在实际开发过程中应用广泛。 ##### (1)静态多态(Static Polymorphism) 也叫作编译时期多态,通常体现为方法重载的形式。当多个方法拥有相同的名称但是参数列表各不相同时,则认为发生了重载现象。 ```java class Calculator { int add(int a, int b){ return a+b; } double add(double a, double b){ return a+b; } } public class StaticPolyExample{ public static void main(String []args){ Calculator calc=new Calculator(); System.out.println(calc.add(5,7)); // 输出整数加法结果 System.out.println(calc.add(5.5,7.8)); // 输出浮点数加法结果 } } ``` 这里展示了同一个名字 `add` 下面存在两套完全独立的操作逻辑,分别适用于不同类型的数据输入情况[^3]。 ##### (2)动态多态(Dynamic Polymorphism) 又名运行时多态,主要是基于方法覆盖的基础上形成的。只要某个基类型引用指向派生出来的实体对象的时候,就会触发这样的机制。 ```java class Vehicle { void run(){ System.out.println("Vehicle running..."); } } class Car extends Vehicle { @Override void run(){ System.out.println("Car speeding up!!"); } } public class DynamicPolyDemo{ public static void main(String []args){ Vehicle v; // 声明的是超类类型的变量v v= new Car(); // 将其赋值给子类创建的对象car v.run(); // 执行的结果取决于当前所指代的实际对象是什么样的 // 此处最终输出"Car speeding up!!" } } ``` 上述案例很好地诠释了即使表面上看起来像是调用了基础版本的动作,但由于背后隐藏着真正的目标身份差异,因而表现出截然不同的动作表现[^3]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值