Java中的抽象类(Abstract Class)是一种特殊类型的类,它无法被实例化,只能被用作其他类的基础。抽象类用于定义具有共同特征和行为的一组相关类的共同结构和方法。抽象类可以包含抽象方法(没有具体实现的方法)和具体方法(有实际实现的方法)。
文章目录
- 抽象类_abstract,不可被实例化:
- 格式:
- 但是可以创建抽象类的对象变量(object variable),但是这样一个变量只能引用子类的对象。
- 好处:类似与方法重载,能够使用其特定的方法
- 抽象方法_abstract,不可被实例化 ,子类必须实现
- 抽象类的主要特点包括:
- 6. 可以有构造方法: 这些构造方法在子类实例化时可以被调用【给子类对象赋值】,通常用于初始化抽象类中的字段。
- 7.抽象类的子类要么重写抽象类中的所有抽象方法要么是抽象类:
- 详细地讨论一下。
- 举例子;
抽象类_abstract,不可被实例化:
作为他类的基类,用于定义共同的特征和行为,抽象类中的抽象方法未明确具体的方法
尽量将字段和方法(不论是否为抽象类)放在超类(不论是否是abstract)中
父类具有的是一般性,也可能抽象。
但从某种角度来说,其作为派生其他类的基类,而不是用到自己的想要的方式的特点实例。
如:
Person|——————————————————————————————| |Employee Student
格式:
[修饰符]abstract class ClassName [extends 父类] [implements 接口列表]{成员内容}
但是可以创建抽象类的对象变量(object variable),但是这样一个变量只能引用子类的对象。
Person p =new Student();
p是抽象类型Person的一个变量,引用了非抽象子类Student的一个实例。
其中三角形和长方形的类中的实现了面积的方法是具体的,不再是抽象类了。
好处:类似与方法重载,能够使用其特定的方法
抽象类可以用作一个通用的基类,它定义了一组通用的属性和方法。然后,具体的子类可以继承这个抽象类,并根据具体的需求来实现或扩展其中的方法。这种结构允许你在处理多个不同的子类时,使用抽象类类型的引用,从而获得多态性和灵活性的好处。
抽象方法_abstract,不可被实例化 ,子类必须实现
==其相当于子类实现本体的具体的方法的**占位符**==。
[修饰符]abstract 返回类型 方法名 ([参数列表]) [throws 异常列表];
抽象方法没有方法体,直接 分号;结束
含有抽象方法的类必须是抽象类,不能被实例化
抽象方法必须在子类中实现
如果抽象类中没有抽象方法,在子类在定义方法。就不能用父类引用子类中新增的内容了(和多态中类似,方法表)
扩展抽象类:
(1)保留抽象类的部分或者所有抽象方法仍未定义,这样子类也必须标记为抽象类;
// 抽象类
abstract class Animal {abstract void makeSound(); // 抽象方法
}// 抽象子类,因为没有实现抽象方法
abstract class Bird extends Animal {// 这里没有提供对抽象方法 makeSound 的实现
}// 具体子类,实现了抽象方法,可以被实例化
class Dog extends Animal {@Overridevoid makeSound() {System.out.println("Dog barks");}
}// 具体子类,实现了抽象方法,可以被实例化
class Cat extends Animal {@Overridevoid makeSound() {System.out.println("Cat meows");}
}
Bird 是一个抽象子类,因为它继承了抽象父类 Animal,但没有提供对抽象方法 makeSound 的实现。而 Dog 和 Cat 都是具体子类,它们实现了抽象方法 makeSound,因此可以被实例化。
(2)定义全部方法,子类就不会抽象了。
// 抽象类
abstract class Shape {abstract double calculateArea(); // 抽象方法double calculatePerimeter() {return 0; // 这里只是示范,具体计算逻辑需要实现类提供}
}// 具体子类,实现了抽象方法,可以被实例化
class Circle extends Shape {double radius;Circle(double radius) {this.radius = radius;}@Overridedouble calculateArea() {return Math.PI * radius * radius;}@Overridedouble calculatePerimeter() {return 2 * Math.PI * radius;}
}// 具体子类,实现了抽象方法,可以被实例化
class Rectangle extends Shape {double width;double height;Rectangle(double width, double height) {this.width = width;this.height = height;}@Overridedouble calculateArea() {return width * height;}@Overridedouble calculatePerimeter() {return 2 * (width + height);}
}
抽象类的主要特点包括:
强制子类必须按照特定的格式进行方法重写
抽象方法所在的类就是抽象类
-
不能被实例化:不能使用
new
关键字直接创建抽象类的实例。 -
可以包含抽象方法:抽象类可以定义抽象方法,这些方法没有实际的代码实现,只有方法签名。子类必须实现抽象类中的所有抽象方法。
如果一个类包含至少一个抽象方法,那么这个类必须声明为抽象类。
-
可以包含具体方法:抽象类也可以包含具体的方法实现,这些方法在抽象类中有默认的实现,子类可以选择性地覆盖这些方法。
-
用于继承:其他类可以继承抽象类,并通过实现抽象方法来提供具体的实现。子类继承了抽象类的属性和方法。
-
用于多态:抽象类可以用于实现多态性,通过父类引用指向子类对象。
6. 可以有构造方法: 这些构造方法在子类实例化时可以被调用【给子类对象赋值】,通常用于初始化抽象类中的字段。
虽然抽象类本身不能被实例化,但是抽象类的构造方法仍然有其用途。抽象类的构造方法在以下几种情况下是有用的:
-
初始化抽象类的字段: 抽象类可以包含字段(成员变量),这些字段可以在构造方法中进行初始化。子类在实例化时会调用父类的构造方法来初始化父类的字段。
-
在子类构造方法中调用: 当子类实例化时,它的构造方法会隐式或显式地调用父类的构造方法,以确保父类的初始化逻辑得以执行。
-
构造方法的继承: 子类继承了父类的构造方法,尽管不能直接实例化抽象类,但子类在实例化时仍然需要调用适当的构造方法,以初始化继承自父类的字段。
-
调用抽象类中的方法: 构造方法也可以用于调用抽象类中的其他方法,无论这些方法是抽象的还是具体的。这些方法可能在子类的构造方法中执行特定的初始化逻辑。
尽管抽象类本身不能被实例化,但构造方法在创建其子类的对象时扮演着关键的角色。子类的构造方法在执行时会先调用父类的构造方法,以确保继承链中的初始化步骤得以完成。这有助于保持继承关系中的数据完整性和一致性。
7.抽象类的子类要么重写抽象类中的所有抽象方法要么是抽象类:
如果一个类继承了一个抽象类,并且不是抽象类本身,那么它要么必须提供实现来覆盖抽象类中的所有抽象方法,要么就必须自己声明为抽象类。如果子类没有提供实现,那么它也必须声明为抽象类。
以下是一个简单的Java抽象类的示例:
abstract class Animal {String name;Animal(String name) {this.name = name;}abstract void makeSound(); // 抽象方法,子类必须实现void eat() {System.out.println(name + " is eating."); // 具体方法}
}class Dog extends Animal {Dog(String name) {super(name);}void makeSound() {System.out.println(name + " barks.");}
}class Cat extends Animal {Cat(String name) {super(name);}void makeSound() {System.out.println(name + " meows.");}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");Cat cat = new Cat("Whiskers");dog.makeSound();cat.makeSound();dog.eat();cat.eat();}
}
在这个示例中,Animal
是一个抽象类,它定义了一个抽象方法makeSound()
和一个具体方法eat()
。Dog
和Cat
是Animal
的子类,它们必须实现makeSound()
方法。在Main
类中,通过多态性调用不同子类的方法。
抽象类的子类在继承抽象类时,通常必须实现抽象类中的所有抽象方法。抽象类是一种不能被实例化的类,它可以包含普通的方法和属性,也可以包含抽象方法。抽象方法是在抽象类中声明但没有提供具体实现的方法,它相当于一种约定,要求子类必须提供具体的实现。
······
当一个类继承一个抽象类时,如果该子类本身不是抽象类,那么它必须提供实现抽象类中所有抽象方法的具体实现。如果子类没有实现抽象类中的全部抽象方法,那么这个子类也必须被声明为抽象类。
·······
在面向对象编程中,抽象类和抽象方法用于定义一个通用的接口或者约定,以便子类可以继承并提供具体的实现。这种机制能够强制子类按照预期的方式来实现方法,从而保证代码的一致性和可维护性。
详细地讨论一下。
-
抽象方法(Abstract Methods): 抽象方法是在抽象类中声明的方法,它没有具体的实现代码,只有方法签名。子类必须实现抽象类中的抽象方法。这适用于在不同的子类中有不同的实现,而且你希望强制子类提供自己的实现。抽象方法通常用于定义基本操作,但这些操作在不同的子类中可能有不同的行为。
-
成员方法(Concrete Methods): 成员方法是在抽象类中有具体实现的方法。这些方法可以在抽象类中提供通用的、共享的实现,以避免在每个子类中重复编写相同的代码。子类可以选择性地覆盖这些方法,以适应特定的需求。成员方法通常用于实现通用的功能,这些功能在多个子类中都可以共享。
总之,你可以这样理解:
-
使用抽象方法:当你希望在不同的子类中有不同的实现,而且这些实现在子类中是必需的时,你应该使用抽象方法。抽象方法强制子类提供自己的实现,确保基类的方法在子类中被正确覆盖。
-
使用成员方法:当你有一些通用的、可复用的代码实现,可以在抽象类中提供默认的具体实现。子类可以直接继承这些方法,避免重复编写相同的代码。子类也可以选择性地覆盖这些方法,以适应特定需求。
需要注意的是,抽象类可以同时包含抽象方法和成员方法,这取决于你的设计需求。通过合理地使用抽象方法和成员方法,可以在代码中实现良好的组织和重用。
举例子;
package oop_useAbstractClass;// 定义一个抽象类 Shape,用于表示各种几何图形
public abstract class Shape {public int width; // 用于存储几何图形的宽度public int height; // 用于存储几何图形的高度// 构造方法,用于初始化宽度和高度public Shape(int width, int height) {this.width = width;this.height = height;}// 声明一个抽象方法 area(),用于计算图形的面积public abstract double calculateArea();
}
package oop_useAbstractClass;// 长方形类,继承自抽象类 Shape
public class Rectangle extends Shape {// 构造函数,接受长方形的长度和宽度作为参数public Rectangle(int length, int width) {// 调用父类的构造函数来初始化长度和宽度super(length, width);}// 重写父类中的抽象方法,计算长方形的面积@Overridepublic double calculateArea() {// 长方形的面积计算公式:长度 * 宽度return width * height;}
}
package oop_useAbstractClass;public class Triangle extends Shape {public Triangle(int width, int height) {super(width, height);}// 重写父类中的抽象方法,计算三角形面积的功能@Overridepublic double calculateArea() {return 0.5 * width * height;}
}
package oop_useAbstractClass;public class ShapeTest {public static void main(String[] args) {// 创建一个长方形对象并初始化其长和宽Rectangle rectangle = new Rectangle(5, 4);// 计算并输出长方形的面积System.out.println("长方形的面积为:" + rectangle.calculateArea());// 创建一个三角形对象并初始化其底边和高Triangle triangle = new Triangle(2, 5);// 计算并输出三角形的面积System.out.println("三角形的面积为:" + triangle.calculateArea());}
}