Java 中 final 和 abstract 的区别


在使用 Java 时,理解 final 和 abstract 的概念对于编写高效且易于维护的代码至关重要。虽然 final 和 abstract 在面向对象编程中都扮演着重要的角色,但它们具有不同的用途。在本文中,我们将探讨 final 和 abstract 关键字在 Java 中的语法和用法,以及它们的不同实现方式。

语法

要定义一个 final 类或方法,我们在类或方法声明之前使用关键字“final”。例如,一个 final 类将定义如下:

final class MyClass {
   // Class implementation
}

要定义一个 abstract 类或方法,我们在类或方法声明之前使用关键字“abstract”。例如,一个 abstract 类将定义如下:

abstract class MyAbstractClass {
   // Class implementation
}

语法解释

关键字 "final" 用于指示一个类、方法或变量不能被修改或重写。final 类不能被子类化,final 方法不能在任何子类中被重写。此外,final 变量一旦赋值就不能重新赋值。

另一方面,关键字 "abstract" 用于指示一个类或方法是不完整的,必须由另一个类扩展或实现。abstract 类不能直接实例化,并且它可能包含 abstract 方法,这些方法必须由其子类实现。

方法 1:Final

在这种方法中,我们将重点关注 final 关键字的用法。使用 final 的主要目的是在 Java 中创建不可变实体。不可变对象是指其状态一旦创建就不能更改的对象。

算法

  • 将类或方法声明为 final。

  • 在类或方法中实现所需的功能。

  • 防止其他类或子类进行任何进一步的修改。

示例

final class ImmutableClass {
   private final String name;

   public ImmutableClass(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

public class Main {
   public static void main(String[] args) {
      ImmutableClass immutableObject = new ImmutableClass("Hello");
      System.out.println(immutableObject.getName());
   }
}

输出

Hello

方法 1 中代码的解释

ImmutableClass 被声明为不可变且不可扩展的,因为在声明期间包含了“final”关键字。它包含一个名为“name”的单个私有实例变量,该变量也被标记为 final,以防止在构造函数中初始赋值后进行修改。

ImmutableClass 的构造函数接受一个名为 name 的 String 参数,并将它的值赋给 name 变量。这确保了 name 变量只能在对象创建期间设置一次,并且之后不能修改。

在 ImmutableClass 中,有一个公共方法 getName() 用于获取对象的名称。由于 name 元素被声明为私有,因此必须阻止外部访问它,因此需要实现此查找工具。我们的程序入口点从 Main 类的 main() 函数开始,我们用参数“Hello”实例化一个 ImmutableClass 对象。

初始化后,我们将新实例存储在内存节省变量 immutableObject 中。我们通过将 System.out.println() 的输出流设置为 immutableObject 的 getName() 方法的返回值来结束我们的 main 函数,以便我们的程序通过在屏幕上显示“Hello”(我们最初指定的名称)来显示成功的执行。

方法 2:Abstract

在这种方法中,我们将重点关注 abstract 关键字的用法。abstract 类用于提供公共接口并为一组相关类定义公共行为。

算法

  • 将类声明为 abstract。

  • 定义 abstract 方法,这些方法应该由子类实现。

  • 在 abstract 类中实现公共功能。

示例

abstract class Shape {
   protected String color;

   public Shape(String color) {
      this.color = color;
   }

   abstract double getArea();
}

class Circle extends Shape {
   private double radius;

   public Circle(String color, double radius) {
      super(color);
      this.radius = radius;
   }

   @Override
   double getArea() {
      return Math.PI * radius * radius;
   }
}

public class Main {
   public static void main(String[] args) {
      Circle circle = new Circle("Red", 2.5);
      System.out.println("Color: " + circle.color);
      System.out.println("Area: " + circle.getArea());
        
   }
}

输出

Color: Red
Area: 19.634954084936208

Shape 类使用 abstract 关键字声明为 abstract 类。abstract 类不能被实例化,这意味着不能直接创建 Shape 类的对象。Shape 类有一个名为 color 的受保护实例变量和一个接受 color 参数并将其值赋给 color 变量的构造函数。

Shape 类还声明了一个名为 getArea() 的 abstract 方法。在编程过程中,abstract 方法在创建代码实现的框架和结构方面发挥着关键作用。具体来说,使用此工具集,开发人员可以创建方法和结构,而无需立即在运行时确定它们,而是将它们留待以后从具体子类(即引入类别之外的类)进一步开发。

让我们具体研究 getArea() 在这里是如何相关的:简而言之,计算面积取决于形状分类和各种开发者使用的子类型因素;因此,将此变化因素放入非立即或独立开发中,允许任何具体子类实现自定义,而无需担心在子级创建之前表达的整体结构中断或完整性维护问题。此外,关于我们在这里的基础工作,Shape 可以被视为由 Circle 扩展为这样的子类,并进一步进行调制以集成到具有类似模板方法的开发的其他结构中。它添加了一个名为 radius 的私有实例变量,并带有一个同时接受 color 和 radius 参数的构造函数。Circle 的构造函数使用 super 关键字调用其超类 (Shape) 的构造函数来初始化 color 变量。然后它将 radius 参数赋给 Circle 类的 radius 变量。

Circle 类重写了从 Shape 类继承的 getArea() 方法。在这种情况下,它使用公式:π * radius * radius 计算圆的面积。Math.PI 常量表示 π 的值(约为 3.14159)。

此编程序列的基础是 Main 类,在其中我们可以找到 main 方法 - 建立程序的起点。在这个方法中,我们启动一个 Circle 对象,最初半径为 2.5,颜色为“红色”。此新对象从其各自的两个构造函数中获取信息:首先调用 Circle 构造函数,然后在重置其颜色值时调用 Shape 构造函数的帮助。最后,我们将“circle”指定为此特定实例的变量名。

最后,使用 circle.color 访问 circle 对象的 color 变量并将其打印到控制台。还对 circle 对象调用 getArea() 方法,并将返回值也打印到控制台。

Java 中 final 和 abstract 的区别

区别

方法 1:Final

方法 2:Abstract

实例化

允许实例化类

不能直接实例化

继承

不能被子类化

允许子类化

方法重写

方法不能被重写

abstract 方法必须由子类实现

可修改性

防止修改类、方法或变量

为在子类中修改和扩展提供蓝图

用法

用于创建不可变实体或强制执行特定行为

用于为相关类定义公共接口和行为

结论

总之,虽然 final 和 abstract 具有不同的用途,但它们都是 Java 编程中的重要工具。通过适当使用它们,您可以编写更健壮、更灵活、更易于维护的代码,这些代码符合设计原则并满足特定需求。无论是创建不可变实体还是建立公共接口,final 和 abstract 关键字都有助于开发高质量的 Java 应用程序。

更新于:2023年7月28日

2K+ 次浏览

启动您的 职业生涯

完成课程获得认证

开始学习
广告