在Java中,抽象类是一种特殊的类,它不能被实例化(即不能创建抽象类的实例对象),主要用于为子类提供通用的模板。抽象类通常用于描述一个类族的共性,并为子类定义必须实现的方法
抽象类中声明只有方法头、没有方法体的抽象方法。抽象类用于描述抽象的概念,其中的抽象方法约定了多个子类共用的方法头,每个子类可以根据自身实际情况,给出抽象方法的具体实现。
抽象类(Abstract Class)
抽象类是一个不能被实例化的特殊类,它主要用于作为其他类的基类,为这些子类提供通用的结构和行为模板。抽象类可以包含属性、非抽象方法(有具体实现的方法)、以及最重要的——抽象方法。
抽象方法(Abstract Method)
抽象方法是在抽象类中声明的只有方法头(包括返回类型、方法名和参数列表)而没有方法体的方法。它的关键特征是使用 abstract
关键字进行修饰,并且不包含任何具体的代码实现。这是因为抽象方法定义了一个规范或契约,它规定了所有继承这个抽象类的子类必须实现这个方法。
理解与应用
共用方法头: 抽象类通过抽象方法定义了一系列接口或者说是约定,这些方法在所有子类中具有相同的方法签名。这意味着无论子类如何实现这些方法,它们的输入参数和返回类型都是一致的。
灵活的实现: 每个子类可以根据自身的特性和需求,自由地给出抽象方法的具体实现。这样,在设计上就允许各个子类对抽象方法有不同的功能实现,从而满足各自业务逻辑的需求,同时又保持了一定程度上的统一性。
设计模式与原则: 抽象类及其抽象方法体现了“面向接口编程”而非“面向实现编程”的设计原则。它鼓励开发者关注于接口的设计和维护,而不是过于关注具体的实现细节,从而提高代码的可扩展性和可维护性
定义抽象类: 使用 abstract
关键字来声明一个抽象类。抽象类可以包含抽象方法(没有具体实现的方法)、非抽象方法以及变量。
声明抽象方法:[权限修饰符] abstract 返回值类型 方法名(参数表);
声明抽象类:
[权限修饰符] abstract class 类名
{
成员变量;
abstract 方法名( ); //定义抽象方法
}
e.g
public abstract class Animal {
// 抽象方法
public abstract void makeSound();
// 非抽象方法
public void sleep() {
System.out.println("The animal is sleeping.");
}
}
说明:抽象类中也可以定义非抽象方法。但是,只要类中有抽象方法,就必须把这个类声明为抽象类。
抽象类的子类必须完成父类定义的每一个抽象方法,除非该子类也是抽象类。它的主要用途是用来描述概念性的内容,这样可以提高开发效率,更好地统一用户“接口”。
子类必须实现抽象方法: 当一个非抽象类继承自抽象类时,它必须提供对父类中所有未实现的抽象方法的具体实现。这是因为抽象方法定义了一个契约或接口,表明所有实现这个抽象类的子类都应具备这些功能。如果子类没有提供抽象方法的实现,则该子类也必须声明为抽象类。
概念性描述与提高开发效率: 抽象类通常用来表示一种抽象的概念或主题,而不是具体的事物。例如,可以有一个抽象类 Animal
,其中包含了动物共有的属性(如名字、年龄)以及行为(如吃、睡),但具体的“发出声音”等行为由子类(如 Dog
和 Cat
)根据各自特点来实现。这样,抽象类就提供了一个通用的框架,使得开发者在处理具有相似特征的对象时,能够快速构建基础结构,并专注于特定于子类的差异性部分,从而提高开发效率。
统一用户“接口”: 这里的“接口”不仅指代Java语言层面的interface,更广泛地指代系统的交互界面或功能入口点。通过抽象类规定的一系列抽象方法,所有继承它的子类都遵循相同的接口规范,这意味着客户端代码可以通过抽象类类型的引用调用这些方法,而不必关心实际操作的是哪一个子类实例。这种设计有助于保持系统内部组件间的松耦合,增强了代码的可扩展性和可维护性。
实例:利用抽象类表示多类图书
e.g.
abstract class Book
{
int bookPage; //图书页码
float discount; //图书折扣
double price; //图书价格
public Book(int bookPage,float discount) //构造方法不能声明为抽象方法
{
this.bookPage = bookPage;
this.discount = discount;
}
abstract void show_kind(); //显示图书种类
abstract double getPrice(int bookPage,float discount); //计算价格
public void show_price() //显示价格
{
System.out.println("This book's price is "+price);
}
}
class Science_book extends Book //定义科技书类
{
public Science_book(int bookPage,float discount)
{
super(bookPage, discount); //引用父类的构造方法
}
public void show_kind() //实现抽象方法
{
System.out.println("The book's kind is science");
}
public double getPrice(int bookPage,float discount) //实现抽象类方法
{
return bookPage*0.1*discount;
}
}
class Literature_book extends Book //定义文艺书类
{
public Literature_book(int bookPage,float discount)
{
super(bookPage, discount);
}
public void show_kind()
{
System.out.println("The book's kind is literature");
}
public double getPrice(int bookPage,float discount)
{
return bookPage*0.08*discount;
}
}
class Teaching_book extends Book //定义教材类
{
public Teaching_book(int bookPage,float discount)
{
super(bookPage, discount);
}
public void show_kind()
{
System.out.println("The book's kind is teaching book");
}
public double getPrice(int bookPage,float discount)
{
return bookPage*0.05*discount;
}
}
public class Booksell
{
public static void main(String args[])
{
Science_book sb = new Science_book(530,0.7f); //创建科技书类对象
sb.price = sb.getPrice(530,0.7f); //引用科技书类方法,计算图书价格
sb.show_kind(); //显示图书种类
sb.show_price(); //引用父类方法,显示图书价格
Literature_book lb=new Literature_book(530,0.7f); //创建文艺书类对象
lb.price = lb.getPrice(530,0.7f);
lb.show_kind();
lb.show_price();
Teaching_book tb = new Teaching_book(530,0.7f); //创建教材类对象
tb.price = tb.getPrice(530,0.7f);
tb.show_kind();
tb.show_price();
}
}
定义了一个抽象类
Book
和三个具体子类:Science_book
(科技书类)、Literature_book
(文艺书类)和Teaching_book
(教材类)。每个类都有自己的特点,但都遵循了父类Book
设定的结构。
抽象类 Book:
- 定义了3个成员变量:
bookPage
(图书页码),discount
(图书折扣)和price
(图书价格)。- 提供了一个构造方法,用于初始化图书的页码和折扣,注意构造方法不能声明为抽象方法。
- 定义了两个抽象方法:
show_kind()
用于显示图书种类,getPrice(int bookPage, float discount)
用于计算图书的价格。- 提供了一个非抽象方法
show_price()
用于显示图书的价格,但在主函数中调用时需要先通过子类的方法计算价格并赋值给price
变量。子类 Science_book、Literature_book 和 Teaching_book:
- 每个子类都继承自抽象类
Book
并重写了show_kind()
方法以实现具体的显示图书种类的功能。- 同样,每个子类也都实现了
getPrice(int bookPage, float discount)
抽象方法,根据各自类型的图书计算出不同的价格。Booksell 类的 main() 函数:
- 创建了三种不同类型图书的对象,并分别调用了它们的
show_kind()
方法来显示图书种类。- 调用每个对象的
getPrice()
方法来计算价格,并将结果赋值给price
成员变量。- 最后调用
show_price()
方法来显示每本书的具体价格。
接口(interface)可以被用来实现类间多继承结构。接口内部只能定义 public 的抽象方法和静态的、公有常量。所有的方法需要在实现接口的类中实现。
接口提供了方法声明与实现相分离的机制,使实现接口的多个类表现出相同的行为模式。每个实现接口的类可以根据各自要求,给出抽象方法的具体实现。
在Java中,接口(Interface)是一个特殊的类型,它定义了一组方法签名(包括返回类型、方法名和参数列表),但不提供方法的实现。接口用于规范类的行为或服务,是一种强制性的契约,任何实现了该接口的类都需要提供接口所声明的所有方法的具体实现。
接口声明:
[访问权限] interface 接口名 [extends 父接口名]
接口实现:
class 类名 [extends 父类名] implements 接口名列表
{
类体
}
一个类可以实现多个接口,中间用逗号隔开。
接口特点:
接口不存在最高层,与类的最高层为Object类是不同的。
接口中的方法只能被声明为public和abstract,如果不声明,则默认为public abstract
接口中的成员变量只能用public、static和final来声明,如果不声明,则默认为public static final。
接口中只给出方法名、返回值和参数表,而不能定义方法体
e.g
public interface Shape1
{
public static final double PI=3.14159;
public abstract double area(); //计算图形面积
public abstract double volume(double x); //计算图形体积
public abstract void show_height(); //显示图形高度
}
public class Circle1 implements Shape1
{
double radius;
public Circle1(double r)
{
radius = r;
}
public double area()
{
return PI*radius*radius;
}
public double volume( double x)
{
return 0;
}
public void show_height(){}
public static void main(String args[])
{
Circle1 circle=new Circle1(3);
System.out.println("Radius="+circle.radius+ " Area="+circle.area());
}
}
定义了一个名为
Shape1
的接口和一个实现该接口的类Circle1
。接口 Shape1:
- 定义了一个静态常量
PI
,其值为圆周率。- 定义了三个抽象方法:
area()
(计算图形面积)、volume(double x)
(计算图形体积)以及show_height()
(显示图形高度)。因为是接口中的方法,默认都是public abstract
类型,即不需要显式声明。类 Circle1:
- 实现了
Shape1
接口,这意味着它必须提供接口中所有抽象方法的具体实现。- 定义了一个私有成员变量
radius
用于存储圆的半径,并在构造方法中初始化。- 实现了
area()
方法,根据圆的半径计算并返回圆的面积。- 对于
volume(double x)
方法,由于圆只有一个二维属性(半径),所以在这个示例中没有实际意义,因此简单地返回0。在实际编程中,如果圆不是一个立体图形,可能需要抛出异常或修改接口以适应实际情况。- 实现了
show_height()
方法,但在此场景下,圆的高度没有具体含义,因此方法体为空。同样,在实际应用中应根据需求进行合理处理。主函数 main():
- 创建了一个
Circle1
类的对象circle
,并将半径设置为3。- 输出了创建对象的半径和通过调用
area()
方法计算得到的面积。