关于Java:抽象类可以有构造函数吗?

Can an abstract class have a constructor?

抽象类可以有构造函数吗?

如果是这样,如何使用它以及用于什么目的?


是的,抽象类可以有一个构造函数。考虑一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
abstract class Product {
    int multiplyBy;
    public Product( int multiplyBy ) {
        this.multiplyBy = multiplyBy;
    }

    public int mutiply(int val) {
       return multiplyBy * val;
    }
}

class TimesTwo extends Product {
    public TimesTwo() {
        super(2);
    }
}

class TimesWhat extends Product {
    public TimesWhat(int what) {
        super(what);
    }
}

超类Product是抽象的,有一个构造函数。具体类TimesTwo有一个构造函数,它只对值2进行硬编码。具体类TimesWhat有一个构造函数,允许调用方指定值。

抽象构造函数通常用于强制类约束或不变量,例如设置类所需的最小字段。

NOTE: As there is no default (or no-arg) constructor in the parent
abstract class, the constructor used in subclass must explicitly call
the parent constructor.


如果处于以下情况之一,您将在抽象类中定义构造函数:

  • 你想表演一些初始化(到抽象类)在实际实例化子类发生
  • 您已在中定义了最终字段抽象类,但你没有在声明中初始化它们在这种情况下,你必须初始化这些的构造函数领域

注意:

  • 您可以定义多个建设者(不同论据)
  • 你能(应该?)定义你的一切施工人员受到保护(使他们公众是毫无意义的)
  • 子类构造函数可以调用抽象的一个构造函数类;它甚至可能不得不称之为(如果没有arg构造函数在抽象类中)

在任何情况下,不要忘记,如果不定义构造函数,编译器将自动为您生成一个构造函数(这个构造函数是公共的,没有参数,什么也不做)。


是的,它可以有一个构造函数,并且它的定义和行为与任何其他类的构造函数一样。除了抽象类不能直接实例化,只能扩展,因此使用总是来自子类的构造函数。


对!抽象类可以有构造函数!

是的,当我们将类定义为抽象类时,它不能被实例化,但这并不意味着抽象类不能有构造函数。每个抽象类必须有一个具体的子类,该子类将实现该抽象类的抽象方法。

当我们创建任何子类的对象时,相应继承树中的所有构造函数都在自上而下的方法中被调用。同样的情况也适用于抽象类。虽然我们不能创建抽象类的对象,但是当我们创建抽象类的具体子类对象时,会自动调用抽象类的构造函数。因此,我们可以在抽象类中有一个构造函数。

注意:非抽象类不能有抽象方法,但抽象类可以有非抽象方法。原因与构造函数类似,不同之处在于我们可以调用super()而不是自动调用。另外,没有什么能像抽象构造函数那样有意义。


不仅如此,它总是如此。如果不指定一个,那么它有一个默认的无参数构造函数,就像其他任何类一样。事实上,所有类,包括嵌套类和匿名类,如果没有指定一个,都会得到一个默认的构造函数(对于匿名类,不可能指定一个,所以您总是会得到默认的构造函数)。

有构造函数的抽象类的一个好例子是日历类。您可以通过调用calendar.getInstance()获得calendar对象,但它也有受保护的构造函数。它的构造函数受到保护的原因是只有它的子类才能调用它们(或者同一个包中的类,但是由于它是抽象的,所以不适用)。公历日历是一个扩展日历类的例子。


抽象类可以有一个构造函数,但不能创建抽象类的对象,那么如何使用该构造函数?

当您继承子类中的抽象类时,您可以通过子类中的super(value)方法将值传递给它的(abstract)构造函数,而不继承构造函数。

因此,使用super可以在抽象类的构造函数中传递值,据我所知,它必须是方法或构造函数中的第一条语句。


可以,抽象类构造函数通常用于所有子类通用的初始化事件的超级调用。


虽然有很多好的答案,但我想给我2美分。

构造函数不生成对象。它用于初始化对象。

是的,抽象类总是有一个构造函数。如果不定义自己的构造函数,编译器将为抽象类提供默认的构造函数。上面适用于所有类——嵌套类、抽象类、匿名类等。

抽象类(与接口不同)可以具有需要初始化的非最终非静态字段。您可以在抽象类中编写自己的构造函数来实现这一点。但是,在这种情况下,不会有任何默认的构造函数。

1
2
3
4
5
6
7
8
9
public abstract class Abs{
    int i;
    int j;
    public Abs(int i,int j){
        this.i = i;
        this.j = j;
        System.out.println(i+""+j);
    }
}

在扩展抽象类时要小心,必须从每个构造函数显式调用super。任何构造函数调用super()的第一行。如果不显式调用Sub(),Java将为您这样做。以下代码无法编译:

1
2
3
4
5
6
public class Imp extends Abs{

public Imp(int i, int j,int k, int l){
    System.out.println("2 arg");
}
}

您必须像下面的示例那样使用它:

1
2
3
4
5
6
7
public class Imp extends Abs{

public Imp(int i, int j,int k, int l){
    super(i,j);
    System.out.println("2 arg");
}
}


当然,抽象类可以有一个构造函数,一般用类构造函数来初始化字段,所以用抽象类构造函数来初始化抽象类的字段。如果要在子类实例化之前初始化抽象类的某些字段,则需要为抽象类提供一个构造函数。抽象类构造函数还可以用于执行与每个子类相关的代码。这样可以防止代码重复。

我们不能创建抽象类的实例,但是我们可以创建从抽象类派生的类的实例。因此,当创建派生类的实例时,会自动调用父抽象类构造函数。

参考文献:本文


是的。在创建继承类的实例时调用抽象类的构造函数。例如,下面是一个有效的Java程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// An abstract class with constructor
abstract class Base {
Base() { System.out.println("Base Constructor Called"); }
abstract void fun();
    }
class Derived extends Base {
Derived() { System.out.println("Derived Constructor Called"); }
void fun() { System.out.println("Derived fun() called"); }
    }

class Main {
public static void main(String args[]) {
   Derived d = new Derived();
    }

}

这是上述代码的输出,

已调用基本构造函数已调用派生构造函数

参考文献:在此处输入链接说明


考虑一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class Product {
    int value;
    public Product( int val ) {
        value= val;
    }
    abstract public int multiply();
}

class TimesTwo extends Product {
    public int mutiply() {
       return value * 2;
    }
}

超类是抽象的,有一个构造函数。


在具体类中,具体类型fnord的构造函数声明有效地公开了两件事:

  • 代码请求创建fnord实例的一种方法。

  • 一种方法,通过这种方法,从正在构造中的fnord派生的类型实例可以请求初始化所有的基类特性。

虽然可能有一种方法可以单独控制这两种能力,但对于每一种具体的类型,一种定义可以同时实现这两种能力。虽然第一种能力对抽象类没有意义,但第二种能力对抽象类的意义和对其他任何类的意义一样,因此它的声明也是必要和有用的。


正如JavaFuns在这里描述的,这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public abstract class TestEngine
{
   private String engineId;
   private String engineName;

   public TestEngine(String engineId , String engineName)
   {
     this.engineId = engineId;
     this.engineName = engineName;
   }
   //public gettors and settors
   public abstract void scheduleTest();
}


public class JavaTestEngine extends TestEngine
{

   private String typeName;

   public JavaTestEngine(String engineId , String engineName , String typeName)
   {
      super(engineId , engineName);
      this.typeName = typeName;
   }

   public void scheduleTest()
   {
     //do Stuff
   }
}


抽象类可以有一个构造函数,但它不能被实例化。但是抽象类中定义的构造函数可以用于实例化该抽象类的具体类。检查JLS:

It is a compile-time error if an attempt is made to create an instance of an abstract class using a class instance creation
expression.

A subclass of an abstract class that is not itself abstract may be
instantiated, resulting in the execution of a constructor for the
abstract class and, therefore, the execution of the field initializers
for instance variables of that class.


是的,抽象类可以有构造函数!

下面是在抽象类中使用构造函数的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
abstract class Figure {

    double dim1;        
    double dim2;

    Figure(double a, double b) {        
        dim1 = a;        
        dim2 = b;        
    }

    // area is now an abstract method

   abstract double area();

}


class Rectangle extends Figure {
    Rectangle(double a, double b) {
        super(a, b);
    }
    // override area for rectangle
    double area() {
        System.out.println("Inside Area for Rectangle.");
        return dim1 * dim2;
    }
}

class Triangle extends Figure {
    Triangle(double a, double b) {
        super(a, b);
    }
    // override area for right triangle
    double area() {
        System.out.println("Inside Area for Triangle.");
        return dim1 * dim2 / 2;
    }
}

class AbstractAreas {
    public static void main(String args[]) {
        // Figure f = new Figure(10, 10); // illegal now
        Rectangle r = new Rectangle(9, 5);
        Triangle t = new Triangle(10, 8);
        Figure figref; // this is OK, no object is created
        figref = r;
        System.out.println("Area is" + figref.area());
        figref = t;
        System.out.println("Area is" + figref.area());
    }
}

所以我想你知道答案了。


为了实现构造函数链接,抽象类将具有一个构造函数。编译器将super()语句保存在子类构造函数中,该子类构造函数将调用超类构造函数。如果没有抽象类的构造函数,那么违反Java规则,我们就不能实现构造函数链接。


是的,抽象类可以有一个构造函数。在抽象类中,可以根据需要重载任意多个构造函数。这些承包商可以用来初始化扩展抽象类的对象的初始状态。正如我们所知,我们不能创建抽象类的对象,因为对象是由"new"关键字创建的,而不是由构造函数创建的……它们只用于初始化子类对象的状态。


由于抽象类可以具有所有访问修饰符的变量,因此必须将它们初始化为默认值,因此构造函数是必需的。在实例化子类时,将调用抽象类的构造函数并初始化变量。

相反,接口只包含常量变量意味着它们已经初始化。所以接口不需要构造函数。


是的,您当然可以添加一个,正如前面为初始化抽象类变量所提到的那样。但是,如果您不显式声明一个,那么它无论如何都有一个隐式的构造函数,用于"构造函数链接"工作。


类中构造函数的作用是初始化字段,而不是"构建对象"。当你试图创建一个抽象超类的新实例时,编译器会给你一个错误。但是,我们可以通过设置抽象类雇员的变量来继承该雇员并使用其构造函数,请参见下面的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Employee {
  private String EmpName;
  abstract double calcSalary();

  Employee(String name) {
    this.EmpName = name;// constructor of abstract class super class
  }
}

class Manager extends Employee{
 Manager(String name) {
    super(name);// setting the name in the constructor of sub class
 }
double calcSalary() {
    return 0;
 }
}

是的..和其他班一样。它可以有一个构造函数,并在为基类创建对象后调用。