Java 如何实例化一个抽象类
抽象类是在Java中使用”抽象”关键字声明的类。抽象类是面向对象编程(OOP)中四个原则之一的”继承”的概念。继承是指Java类的一个特性,其中一个类被称为”子类”可以继承父类通常被称为”超类”的所有属性。
在Java中,抽象类指的是其他子类可以继承的基础超类。它可以包含抽象方法和非抽象方法。
步骤
- 步骤1: 确定类中具有默认或无实现的方法。
-
步骤2: 移除这些方法的实现。
-
步骤3: 在类声明中添加抽象关键字。
-
步骤4: 在步骤2中修改的方法声明中添加抽象关键字。
-
步骤5: 如果类有需要初始化的实例变量,添加一个构造函数来初始化它们。
-
步骤6: 更新抽象类的任何子类以实现抽象方法或自身变为抽象。
语法
让我们看一下在Java中实例化一个抽象类的语法:
// Abstract Class
abstract class Shape {
public abstract void draw();
}
方法
由于抽象类是不完整的类,不能直接使用”new”关键字实例化。
- 具体子类 - 为了正确实例化一个模糊或不完整的抽象类,可以选择使用一个具体子类。通过无缝地从这个父类扩展,并实现每个方法的要求,用户可以成功地创建和实现这个新实例化的子类,而不会出现错误或不一致的操作。
-
Lambda表达式 - 要从抽象类创建一个对象,你还有另一种选择-使用提供所有抽象的lambda表达式。然后,根据这些签名将此lambda创建分配给兼容的功能接口变量。
实例化抽象类
让我们看一个示例代码片段,以了解抽象类的用法。第一个场景提供了一段具有非抽象类的代码。
示例
class Shape {
public void printName() {
System.out.println("I'm a shape");
}
public float area() {
return 0;
}
public void printDetails() {
this.printName();
System.out.println("... and my area is " + this.area());
}
}
class Circle extends Shape {
private float radius;
public Circle(float radius) {
this.radius = radius;
}
public void printName() {
System.out.println("I'm a circle");
}
public float area() {
return (float) (Math.PI * Math.pow(radius, 2));
}
}
class Rectangle extends Shape {
private float length;
private float width;
public Rectangle(float length, float width) {
this.length = length;
this.width = width;
}
public void printName() {
System.out.println("I'm a rectangle");
}
public float area() {
return length * width;
}
}
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(3.5f), new Rectangle(4.0f, 5.0f) };
for (Shape shape : shapes) {
shape.printDetails();
}
}
}
输出
I'm a circle
... and my area is 38.48451
I'm a rectangle
... and my area is 20.0
Circle和Rectangle类都继承自“Shape”超类的printName()、area()和printDetails()方法。然而,两个类都没有覆盖area()方法来提供自己的实现。
通过在Circle对象上调用printDetails()方法,输出将是“I’m a circle… and my area is 38.48451”。同样,调用Rectangle对象上的printDetails()方法将输出“I’m a rectangle… and my area is 20.0”。这确保了输出反映了基于每个类中提供的具体实现的正确形状及其对应的区域。
示例1:具体子类
// With abstract class
abstract class Shape {
public abstract void printName();
public abstract float area();
public void printDetails() {
this.printName();
System.out.println("... and my area is " + this.area());
}
}
// Concrete class
class Circle extends Shape {
private float radius;
public Circle(float radius) {
this.radius = radius;
}
public void printName() {
System.out.print("I'm a circle");
}
public float area() {
return (float) (Math.PI * Math.pow(radius, 2));
}
}
// Concrete class
class Rectangle extends Shape {
private float length;
private float width;
public Rectangle(float length, float width) {
this.length = length;
this.width = width;
}
public void printName() {
System.out.print("I'm a rectangle");
}
public float area() {
return length * width;
}
}
// Main class
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(10), new Rectangle(5, 10) };
for (Shape shape : shapes) {
shape.printDetails();
}
}
}
输出
I'm a circle... and my area is 314.15927
I'm a rectangle... and my area is 50.0
在上述更新的代码中,Circle和Rectangle类实现了在Shape抽象类中定义的printName()和area()抽象方法。Shape类中的printDetails()方法可以使用这些方法来打印出形状的名称和其对应的面积。
通过使Shape成为一个抽象类,并定义抽象方法,我们确保继承Shape类的任何类都必须为printName()和area()方法提供自己的实现。
示例2:Lambda表达式
interface Nameable {
String getName();
}
abstract class Shape {
private Nameable nameable;
public Shape(Nameable nameable) {
this.nameable = nameable;
}
public abstract float area();
public void printDetails() {
System.out.println("I'm a " + nameable.getName() + " ... and my area is " + this.area());
}
}
class Circle extends Shape {
private float radius;
public Circle(float radius) {
super(() -> "circle");
this.radius = radius;
}
@Override
public float area() {
return (float) (Math.PI * Math.pow(radius, 2));
}
}
class Rectangle extends Shape {
private float width;
private float height;
public Rectangle(float width, float height) {
super(() -> "rectangle");
this.width = width;
this.height = height;
}
@Override
public float area() {
return width * height;
}
}
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(10), new Rectangle(5, 10) };
for (Shape shape : shapes) {
shape.printDetails();
}
}
}
输出
I'm a circle ... and my area is 314.15927
I'm a rectangle ... and my area is 50.0
在我们最近对这段代码的更新中,我们引入了一种改进的方法,通过将Shape分配为一个抽象类,同时使其getName()函数内部化。进一步的改进包括集成一个printName方法,该方法成功利用了getName()的数据来显示每个相应形状的名称。关于Circle和Rectangle子类-它们现在使用lambda表达式重写其相应的getNames方法,以准确识别预期的形式。
结论
总之,抽象类只能通过它们的基类子类来实例化,而不能直接实例化。这是继承的一个概念。
这背后的主要原因是抽象类不是其方法和对象的完整实现,而是由子类用于继承。