Java 第七章:继承、多态、抽象类与接口

Java 第七章:继承、多态、抽象类与接口

在这里插入图片描述

​ 继承和多态性经常一起使用。通过继承,子类可以继承父类的属性和方法,并且可以重写这些方法来实现自己的功能。而通过多态性,可以在父类中定义一个方法,让所有的子类都去实现这个方法,从而实现不同子类的不同行为。这样可以让代码更加灵活、可扩展和易维护。

1.类的继承

继承是一种面向对象编程的概念,它允许一个类继承另一个类的属性和方法。被继承的类称为父类或基类,继承的类称为子类或派生类。子类可以继承父类中所有可见的属性和方法,包括公共、受保护和默认级别的成员变量和方法,但不包括私有成员变量和方法。

例:创建子类对象,观察构造方法执行顺序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

例:在电话类基础上衍生出手机类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

​ Java虽然不允许同时继承两个父类,但不代表没有多继承的关系,可以通过类似“祖父>父>儿子>孙子”的方式实现多代继承。

例:绝大多数动物有眼睛,鼻子和嘴,犬类继承动物类,所以犬类也有眼睛,鼻子和嘴,哈士奇是犬类的一个品种,犬类有的特征哈士奇都有,但哈士奇的眼睛鼻子和嘴并不是从犬类继承的,而是从动物类继承的。

class Animal {                //父类:动物类
    Eyes eyes;
    Nose nose;
    Mouth mouth;
}

class Dog extends Animal{}    //子类:犬类
class Husky extends Dog{}     //子类:哈士奇类

2.Object类

Java中所有的类都是直接或间接继承自Object类。Object类是Java中的基类,它提供了一些常用的方法和属性,可以被其他所有的类继承和使用。

2.1、getClass()方法

getClass()方法:用于获取对象的类对象。可以使用getClass()方法来获取对象的类名、访问类的属性和方法等信息。

语法如下:

getClass().getName();

getClass()方法与toString()方法可以联合使用 。

2.2、toString()方法

toString()方法:用于将对象转换为字符串表示。默认情况下,toString()方法返回对象的类名和内存地址,但可以被子类重写来实现自定义的字符串表示。

例:让学生自我介绍

在这里插入图片描述

2.3、equals()方法

equals()方法:用于比较两个对象是否相等。默认情况下,equals()方法比较的是两个对象的引用是否相等,但可以被子类重写来实现自定义的相等比较。

例:根据身份证号判断是否为同一人

在这里插入图片描述

3.对象类型转换

Java中,对象类型的转换包括向上转型和向下转型两种类型。

3.1 向上转型

向上转型是指将子类对象转换成父类对象的过程。这种转换是自动完成的,无需任何显式的类型转换操作。由于子类继承了父类的属性和方法,因此可以将子类对象看作是父类对象的一种特殊形式,从而可以将子类对象赋值给父类对象。

例,假设有一个Animal类和一个Cat类,Cat类是Animal类的子类。可以使用如下的代码进行向上转型:

javaCopy code
Animal animal = new Cat();

在这个例子中,创建了一个Cat对象,并将其赋值给Animal类型的引用变量animal。由于Cat类是Animal类的子类,因此可以将Cat对象向上转型成Animal对象。

3.2向下转型

向下转型是指将父类对象转换成子类对象的过程。这种转换需要显式的类型转换操作,并且需要确保父类对象实际上是子类对象的实例。如果转换不正确,则会引发ClassCastException异常。

例,假设有一个Animal类和一个Cat类,可以使用如下的代码进行向下转型:

javaCopy codeAnimal animal = new Cat();
Cat cat = (Cat)animal;

在这个例子中,首先将一个Cat对象向上转型成Animal对象,并将其赋值给一个Animal类型的引用变量animal。然后,将animal对象向下转型成Cat对象,并将其赋值给一个Cat类型的引用变量cat。由于animal对象实际上是Cat对象的实例,因此可以将其向下转型成Cat对象。

需要注意,在进行向下转型时需要确保父类对象实际上是子类对象的实例。可以使用instanceof运算符来检查对象的类型,从而避免ClassCastException异常的发生。

4.使用instanceof关键字判断对象类型

instanceof关键字是用于检查对象的类型。它的语法格式为:

javaCopy code
对象 instanceof 类名

其中,对象是要检查的对象,类名是要检查的类名或接口名。如果对象是该类或接口的一个实例,则返回true;否则返回false。

instanceof可以用来检查对象的类型,从而避免进行不正确的类型转换。例如,假设有一个Animal类和一个Cat类,可以使用如下的代码进行类型检查:

javaCopy codeAnimal animal = new Cat();
if (animal instanceof Cat) {
    Cat cat = (Cat)animal;
    // 执行 Cat 类型的操作
} else {
    // 处理 Animal 类型的情况
}

在这个例子中,首先将一个Cat对象向上转型成Animal对象,并将其赋值给一个Animal类型的引用变量animal。然后,使用instanceof检查animal对象是否是Cat类型的实例,如果是,则将其向下转型成Cat对象,并执行Cat类型的操作;否则,处理Animal类型的情况。

需要注意,instanceof只能用来检查对象的类型,不能用来检查基本类型。例如,不能使用instanceof来检查int类型的变量。此外,instanceof也不能用来检查对象的泛型类型。

5.方法的重载

方法的重载(Overloading)是指在同一个类中可以定义多个方法名相同但参数类型、个数或顺序不同的方法。重载方法可以让程序代码更加简洁、清晰,并且可以根据不同的参数类型、个数和顺序进行不同的处理。

方法的重载需要满足以下两个条件:

1.方法名相同

2.参数列表不同,包括参数类型、个数或顺序不同

注意:返回值类型不是方法的重载条件。

例,下面就是一个计算两个整数之和的重载方法:

public int sum(int a, int b) {
    return a + b;
}
public int sum(int a, int b, int c) {
    return a + b + c;
}
public int sum(double a, double b) {
    return (int)(a + b);
}

上面的三个方法都是sum,但是它们的参数列表不同,所以它们是不同的方法。我们可以根据参数的不同类型、个数或顺序调用不同的方法,实现相应的功能。例如:

int result1 = sum(1, 2);
int result2 = sum(1, 2, 3);
int result3 = sum(1.0, 2.0);

通过方法的重载,我们可以使用相同的方法名来完成不同的功能,这样可以提高代码的重用性和可读性。

例:编写不同形式的加法运算方法

在这里插入图片描述

在谈到参数个数可以确定两个方法是否具有重载关系时,会想到定义不定长参数方法。不定长方法语法如下:

返回值 方法名(参数数据类型…参数名称)

例:使用不定长参数重载加法运算方法

在这里插入图片描述

在上述实例中,在参数列表中使用“…”形式定义不定长参数,其实这个不定长参数a就是一个数组,编译器会将“int…a”这种形式看成“int[] a”,所以在add()方法体做累加操作时使用到了for循环语句,在循环中是根据数组a的长度作为循环条件的,最后将累加结果返回。

6.final关键字

final 是 Java 中的一个关键字,可以用来修饰类、方法和变量。使用 final 修饰的类不能被继承,使用 final 修饰的方法不能被子类重写,使用 final 修饰的变量不能被修改。

6.1 final变量

final关键字可以用于修饰变量,被final修饰的变量称为final变量。final变量是指在声明时必须被初始化,并且在程序执行过程中其值不可更改的变量。

final变量的值一旦被赋值就不能再改变,这使得程序具有更好的安全性和稳定性。在Java编程中,final变量通常用来表示常量或配置参数。

例:定义不允许的常量π

在这里插入图片描述

6.2 final方法

final关键字可以用于修饰类、方法和变量。当final用于修饰方法时,该方法就称为final方法。

final方法是指在类中声明的方法,在子类中不能被重写或覆盖。这意味着,当一个方法被声明为final时,它的实现在父类中是最终的,子类不能对其进行修改。

下面是一个示例代码,演示了如何在Java中使用final方法:

csharpCopy codepublic class Animal {
    public final void move() {
        System.out.println("Animal is moving...");
    }
}

public class Cat extends Animal {
    // 重写move方法会引发编译时错误
}

在这个例子中,Animal类定义了一个名为move的final方法。由于move方法被声明为final,它不能在子类中被重写或覆盖。因此,在Cat类中重写move方法会引发编译时错误。

final方法的优点是能够防止子类修改父类中的行为。如果一个方法被声明为final,那么它的实现在所有子类中都是不变的。这可以确保程序的稳定性和可靠性,同时也可以提高程序的执行效率。

6.3 final类

在Java中,final关键字可以用于修饰类,被final修饰的类称为final类。final类是指不能被继承的类,即其子类不能被创建。

当一个类被声明为final时,它的实现在程序执行过程中是最终的,不能被修改或扩展。这意味着,final类的行为在所有的子类中都是不变的,可以确保程序的稳定性和安全性。

下面是一个示例代码,演示了如何在Java中使用final类:

arduinoCopy codepublic final class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
    public static int multiply(int a, int b) {
        return a * b;
    }
}

在这个例子中,定义了一个名为MathUtils的final类。由于MathUtils类被声明为final,它不能被继承,即其子类不能被创建。MathUtils类中包含了两个静态方法add和multiply,这些方法可以被其他类直接调用,无需创建MathUtils类的实例。

final类的优点是可以确保程序的稳定性和安全性,同时也可以提高程序的执行效率。因为final类不能被继承,所以它的实现在所有的子类中都是不变的,这可以防止子类修改或扩展final类的行为。

7.多态

在Java中,多态是指同一种行为或操作作用于不同的对象时,可以产生不同的结果。具体来说,多态可以通过继承和接口实现。

继承多态:子类可以重写父类的方法,当父类的引用指向子类的对象时,调用该方法时会调用子类中的方法实现。这种行为称为动态绑定或运行时绑定。例如:

csharpCopy codepublic class Animal {
    public void move() {
        System.out.println("Animal is moving...");
    }
}

public class Cat extends Animal {
    public void move() {
        System.out.println("Cat is moving...");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.move(); // 输出:Cat is moving...
    }
}

在这个例子中,定义了一个名为Animal的父类和一个名为Cat的子类,Cat类重写了Animal类中的move方法。在主方法中,创建了一个Animal类的引用,指向Cat类的对象。当调用animal.move()方法时,输出的结果为"Cat is moving…",这说明方法的实现是动态绑定的,即运行时决定调用哪个方法。

接口多态:当一个类实现了接口后,可以通过接口类型的引用指向该类的对象。这种行为称为接口多态。例如:

csharpCopy codepublic interface Shape {
    void draw();
}

public class Rectangle implements Shape {
    public void draw() {
        System.out.println("Drawing a rectangle...");
    }
}

public class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing a circle...");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape shape1 = new Rectangle();
        Shape shape2 = new Circle();
        shape1.draw(); // 输出:Drawing a rectangle...
        shape2.draw(); // 输出:Drawing a circle...
    }
}

在这个例子中,定义了一个名为Shape的接口和两个实现了Shape接口的类Rectangle和Circle。在主方法中,创建了两个Shape类型的引用,分别指向Rectangle类和Circle类的对象。当调用shape1.draw()方法和shape2.draw()方法时,分别输出"Drawing a rectangle…“和"Drawing a circle…”,这说明方法的实现也是动态绑定的。

例:万能的绘图方法

在这里插入图片描述

8.抽象类

使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承没有任何意义。定义抽象类的语法如下:

public abstract class Parent{
  abstract void testAbstrac();   //定义抽象方法

抽象类被继承后需要实现其中所有的抽象方法,也就是保证以相同的方法名称,参数列表和返回值类型创建出的非抽象方法,当然也可以是抽象方法。

抽象方法
修饰符 abstract 返回参数 方法名(传入参数);

抽象类 有抽象方法的类一定是抽象类
修饰符 abstract class 类名{
}

9接口

接口是抽象类的延伸,可以将它看作为是纯粹的抽象类,接口中的所有方法都没有方法体。

接口通过关键字“interface”来定义,接口中的方法默认是public abstract类型的,常量是public static final类型的。接口可以被类实现(implements),表示类遵循了该接口的规范,同时必须实现该接口中定义的所有抽象方法。语法如下:

public interface Paintable{
    void draw();        //定义接口方法可省略public abstract关键字
}

一个类可以实现多个接口,但只能继承一个父类。这使得接口成为了Java中实现多继承的一种方式。通过实现多个接口,一个类可以拥有多种类型的行为特征。

接口也可以继承(extends)其他接口,这使得接口可以通过继承机制扩展接口的行为特征。当一个接口继承了另一个接口时,它将自动包含另一个接口中的所有常量和方法定义。

总之,接口提供了一种机制,用于定义类的一组操作行为,并将这些行为规范化,以便在实现类中实现具体的操作行为。

例:将绘图方法设为接口方法

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值