赶紧收藏!2024 年最常见 100道 Java 基础面试题(七)

上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(六)-CSDN博客

十三、抽象类能使用final修饰吗?

在Java中,final关键字有几种不同的用途,但是当它用于类时,它表示该类不能被继承。因此,抽象类不能被声明为final,原因如下:

  1. 继承的目的

    • 抽象类的设计意图是作为其他类的基类,允许其他类通过继承来扩展其功能。如果一个抽象类被声明为final,那么它就失去了作为基类的主要目的,因为它阻止了继承。
  2. 抽象方法的实现

    • 抽象类通常包含一个或多个抽象方法,这些方法没有具体的实现,而是期望继承的子类提供实现。如果抽象类是final的,那么它就不能被继承,因此无法由子类提供这些抽象方法的实现。
  3. 设计模式和原则

    • 在面向对象编程中,抽象类通常用于实现里氏替换原则(Liskov Substitution Principle),这是SOLID原则之一。声明类为final会违背这一原则,因为它阻止了其他类通过继承来重用和扩展基类的行为。
  4. 语法限制

    • 在Java语言规范中,不允许将含有抽象方法的类声明为final。即使抽象类中没有抽象方法,从设计的角度来看,将其声明为final也是不合理的,因为它失去了作为抽象基类的意义。

示例代码

// 尝试将抽象类声明为final将导致编译错误
abstract final class InvalidDesign {
    // 这样的声明是不合法的,因为final和abstract是矛盾的
    public abstract void someAbstractMethod();
}

// 正确的抽象类声明
abstract class ValidDesign {
    public abstract void someAbstractMethod();
    // 可以有具体的方法实现
    public void someConcreteMethod() {
        // 方法实现
    }
}

// 继承ValidDesign的子类
class SubClass extends ValidDesign {
    @Override
    public void someAbstractMethod() {
        // 提供抽象方法的具体实现
    }
}

总结

  • 抽象类不能被声明为final,因为这样做违背了抽象类作为基类被继承和扩展的目的。
  • 在实际编程中,如果一个类被声明为final,那么它通常是具体类,提供了所有方法的具体实现,并且不希望被继承。

十四、接口和抽象类有什么区别?

在Java中,接口(interface)和抽象类(abstract class)都是实现面向对象编程中的抽象化概念的工具,但它们之间存在一些关键的区别:

  1. 定义

    • 抽象类:使用abstract关键字声明,可以包含抽象方法和具体方法。抽象方法没有方法体,而具体方法有完整的实现。
    • 接口:使用interface关键字声明,在Java 8之前,接口中的方法都是隐式地被声明为public abstract的。从Java 8开始,接口也可以拥有默认方法(带有具体实现的方法)和静态方法。
  2. 实现

    • 一个类可以通过extends关键字继承一个抽象类,并且必须提供抽象类中所有抽象方法的实现。
    • 一个类可以通过implements关键字实现多个接口,并且必须提供所有方法的具体实现(除非接口方法被声明为默认方法)。
  3. 构造方法

    • 抽象类可以有构造方法,而接口不能有构造方法。
  4. 访问修饰符

    • 抽象类中的方法可以有多种访问修饰符(如publicprotectedprivate)。
    • 接口中的方法在Java 9之前默认是public的,且不能有privateprotected修饰。从Java 9开始,接口方法可以有private修饰,但仅用于实现默认方法。
  5. 属性

    • 抽象类可以有各种属性,包括实例变量和静态变量。
    • 接口在Java 8之前只能有静态常量。从Java 8开始,接口可以有静态方法和默认方法。
  6. 多继承

    • Java中的类只能继承自一个抽象类,因为多继承会导致“菱形问题”(Diamond Problem)。
    • 一个类可以实现多个接口,没有数量限制,这允许更灵活的设计。
  7. 使用场景

    • 抽象类更适合用来表达一个概念的部分实现,当你想在一个类中提供一些共享的代码时,可以使用抽象类。
    • 接口更适合用来表达一个角色或一个特定的行为,当你想定义一个可以被多个类实现的契约时,可以使用接口。
  8. 实例化

    • 抽象类不能被直接实例化,必须通过其子类实例化。
    • 接口不能被实例化,但可以声明接口类型的引用,并通过该引用来使用实现接口的类的实例。

示例代码

// 抽象类示例
abstract class Animal {
    public abstract void makeSound();
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

// 接口示例
interface Drivable {
    void drive();
}

interface Flyable {
    void fly();
}

// 实现接口的类
class Car implements Drivable {
    public void drive() {
        System.out.println("Car is driving.");
    }
}

// 一个类可以实现多个接口
class Plane implements Drivable, Flyable {
    public void drive() {
        System.out.println("Plane cannot drive, but it can taxi.");
    }

    public void fly() {
        System.out.println("Plane is flying.");
    }
}

总结

  • 接口和抽象类都用于定义抽象概念,但接口更侧重于行为的约定,而抽象类可以提供一些默认的行为和实现细节。
  • 一个类可以实现多个接口,但只能继承一个抽象类。
  • 接口中的方法默认是public的,而抽象类中的方法可以有多种访问修饰符。
  • 抽象类可以有构造方法和属性,而接口(在Java 8之前)除了静态常量外,不能有属性和构造方法。Java 8及以后的版本允许接口有静态方法和默认方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值