当编写一个类时,常常会为该类定义一些方法,这些方法用以描述该类的行为方式,那么这些方法都有具体的实现,即方法体。但在某些情况下,某个父类只是知道其子类应该包含怎样的方法,但无法准确地知道这些子类如何实现这些方法。
例如:定义了一个 Shape(形状)类,这个类应该提供一个计算周长的方法 calPerimeter(float arg),但不同的 Shape 子类对周长的计算方法是不一样的,即 Shape 类无法准确地知道其子类计算周长的方法。代码如下:
// 基类:形状 public class Shape { // 定义圆周率常量 public final float PI = 3.14159f; // 计算周长的方法 public float calPerimeter(float arg) { return 0f; // 提供空实现 } } // 子类:圆 public class Circle extends Shape { public float calPerimeter(float arg) { return PI * arg; } } // 子类:正方形 public class Square extends Shape { public float calPerimeter(float arg) { return arg * arg; } }
上面代码中,Shape 类的 calPerimeter() 方法提供了一个空实现,什么也不做,直接返回 0,我们就可以这样去使用它:
Shape circle = new Circle(); circle.calPerimeter(2.5f); Shape square = new Square(); square.calPerimeter(2.5f);
可能有读者会提出,既然 Shape 类不知道如何实现 calPerimeter() 方法,那就干脆不要管它,将它从 Shape 类删除!但这不是一个好思路,如果删除该方法,会导致上面代码中的 circle.calPerimeter(2.5f) 和 square.calPerimeter(2.5f) 语句会出现语法错误,Shape 类中没有 calPerimeter() 方法。为了解决这个问题,我们不得不将代码做如下调整:
Circle circle = new Circle(); circle.calPerimeter(2.5f); Square square = new Square(); square.calPerimeter(2.5f);
修改后的代码虽然能够正常运行,但是降低了程序的灵活性。如果有一个方法的参数接收一个 Shape 类型的参数,该怎么解决呢?如下:
public void myMethod(Shape shape) { float val = shape.calPerimeter(2.5f); // 错误,会提示没有 calPerimeter 方法 System.out.println("val=" + val); }
如何既能让 Shape 类里包含 calPerimeter() 方法,又无须提供其方法实现呢?答案:将 Square 声明为抽象类,calPerimeter() 声明为抽象方法。
抽象类是在面向对象编程中的一个概念,它是一个不能被实例化的类。抽象类用于定义一组相关的子类的通用行为和属性,它可以包含抽象方法、普通方法、构造方法和成员变量。
抽象类通过关键字 “abstract” 关键字来声明,它可以包含抽象方法(没有实现代码的方法)和普通方法(有实现代码的方法)。抽象方法必须在抽象类中声明,子类继承抽象类后,必须实现抽象方法,否则子类也必须声明为抽象类。
抽象类的主要作用是为子类提供一个公共的模板或规范,它定义了子类应该具有的方法和属性。通过继承抽象类,子类可以继承和重写抽象方法,实现自己的具体逻辑。抽象类在面向对象的设计中起到了重要的作用,它可以提高代码的重用性和可维护性。
Java 中定义抽象类的语法格式如下:
[修饰符] abstract class 类名 { // 成员定义 // 方法定义 // 抽象方法定义 }
说明:
修饰符:可选参数,用于指定抽象类的访问权限,可选值为 public。如果省略则使用默认的访问权限。
类名:必选参数,用于指定抽象类的名称,类名必须是合法的 Java 标识符。一般情况下,要求首字母大写。
将上面的 Shape 类定义为抽象类,代码如下:
/** * 将 Shape 声明为抽象类 * @author hxstrive.com */ public abstract class Shape { // 定义圆周率常量 public final float PI = 3.14159f; // 计算周长的方法,定义为抽象方法 public abstract float calPerimeter(float arg); }
抽象类的主要特点包括:
(1)不能被实例化:抽象类不能直接被实例化,只能被用作其他类的父类。
(2)可以包含抽象方法:抽象类可以包含抽象方法,这些方法只有方法声明,没有具体的实现。注意:抽象类不一定必须包含抽象方法。
(3)可以包含非抽象方法:抽象类可以包含非抽象方法,这些方法有具体的实现。
(4)可以包含成员变量:抽象类可以包含成员变量,这些变量可以被子类继承和使用。
抽象类和普通类之间有以下几个区别:
(1)实例化:抽象类不能直接实例化,即不能使用 “new” 关键字来创建抽象类的对象,而普通类可以直接实例化。
(2)完整性:普通类可以是完整的,即它可以包含成员变量、方法和构造方法的具体实现,而抽象类可以包含抽象方法(没有具体实现的方法)和非抽象方法(有具体实现的方法)。
(3)继承:抽象类可以被其他类继承,子类需要实现抽象类中的抽象方法,或者子类也可以声明为抽象类。普通类也可以被继承,但子类不需要实现任何方法。
(4)多态性:抽象类可以通过多态的方式被引用,即可以使用抽象类的引用变量指向其子类的对象。普通类也可以通过多态的方式被引用。
(5)设计目的:抽象类主要用于定义一组相关的子类的通用行为和属性,它提供了一个模板或规范,子类需要实现抽象方法来完成自己的具体逻辑。普通类没有这个限制,可以直接实例化,也可以被继承和重写。
总的来说,抽象类是一种特殊的类,用于作为其他类的父类,定义一组通用的行为和属性,并强制子类实现抽象方法。普通类没有这些限制,可以直接实例化,也可以被继承和重写。
抽象方法是在面向对象编程中的一个概念,它是一个没有具体实现代码的方法。抽象方法只有方法的声明,没有方法体,用关键字 “abstract” 来声明。
抽象方法的声明包括方法的返回类型、方法名和参数列表,但没有方法体。
抽象方法必须在抽象类中声明,不能在普通类中声明。
抽象方法的具体实现由子类来完成,子类必须实现父类中的所有抽象方法,否则子类也必须声明为抽象类。
抽象方法的作用是为子类提供一个方法的模板或规范,定义了子类应该具有的方法签名(方法名、返回类型和参数列表)。子类通过实现抽象方法来完成自己的具体逻辑。抽象方法在面向对象的设计中起到了重要的作用,它可以提高代码的灵活性和可维护性。
Java 中定义抽象方法的语法格式如下:
[修饰符] 返回类型 方法名([参数类型 参数名[,...]]) [throws 异常类型列表] { // 方法体 }
说明如下:
修饰符:修饰符可以省略,也可以是 public、protected、private、static、final、abstract,其中 public、protected、private 三个最多只能出现其中之一;abstract 和 final 最多只能出现其中之一,它们可以与 static 组合起来修饰方法。例如:public static String 方法名() {}
方法返回值类型:返回值类型可以是 Java 语言允许的任何数据类型,包括基本类型和引用类型;如果声明了方法返回值类型,则方法体内必须有一个有效的 return 语句,该语句返回一个变量或一个表达式,这个变量或者表达式的类型必须与此处声明的类型匹配。除此之外,如果一个方法没有返回值,则必须使用 void 来声明没有返回值。
方法名:方法名的命名规则与成员命名规则基本相同,但通常建议方法名以英文中的动词开头。
形参列表:形参列表用于定义该方法可以接受的参数,形参列表由零组到多组 “参数类型形参名" 组合而成,多组参数之间以英文逗号 (,) 隔开,形参类型和形参名之间以英文空格隔开。一旦在定义方法时指定了形参列表,则调用该方法时必须传入对应的参数值 —— 谁调用方法,谁负责为形参赋值。
异常类型列表:用来声明当前方法可能抛出的异常类型列表,例如:
public void myMethod(int arg1, String arg2) throws IOException,SQLException { //... }
将上面的 Shape 类中的 calPerimeter() 方法声明为抽象方法,代码如下:
/** * 将 Shape 声明为抽象类 * @author hxstrive.com */ public abstract class Shape { // 定义圆周率常量 public final float PI = 3.14159f; // 计算周长的方法,定义为抽象方法 public abstract float calPerimeter(float arg); }
抽象方法的主要特点包括:
(1)没有具体实现:抽象方法只有方法的声明,没有方法体,没有具体的实现代码。
(2)必须在抽象类中声明:抽象方法必须在抽象类中声明,不能在普通类中声明。
(3)子类必须实现:子类继承抽象类后,必须实现父类中的所有抽象方法,否则子类也必须声明为抽象类。
抽象方法和普通方法之间有以下几个区别:
(1)实现方式:抽象方法没有具体的实现代码,只有方法的声明,而普通方法有具体的实现代码。
(2)所属类:抽象方法必须在抽象类中声明,而普通方法可以在抽象类或普通类中声明。
(3)强制实现:子类必须实现抽象类中的所有抽象方法,否则子类也必须声明为抽象类。而普通方法在父类中有默认的实现,子类可以选择性地重写普通方法。
(4)调用方式:抽象方法不能直接调用,需要通过子类的对象来调用。而普通方法可以直接通过对象或类名来调用。
(5)多态性:抽象方法可以通过多态的方式被引用,即可以使用抽象类的引用变量指向其子类的对象。而普通方法也可以通过多态的方式被引用。