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

如果有的话,如何使用它以及用于什么目的?

#1 楼

是的,抽象类可以具有构造函数。请考虑以下问题:

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具有允许调用者指定值的构造函数。

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


注意:由于父类
中没有默认(或无参数)构造函数,因此使用的构造函数子类中的对象必须显式调用
父构造函数。


评论


@乔纳森:为回答所提问题而增加复杂性并没有真正的好处。如果问题是关于范围的,那么是的,将这三种有用的可能性进行对比是有意义的。

–迈克尔·卢瑟福(Michael Rutherfurd)
2010年6月21日,0:50

我认为Jonathon只是想说一个抽象类上的公共构造函数没有任何意义,因为您不能直接实例化一个抽象类(只能通过本身未标记为抽象的派生类型进行实例化)。

–Hobo Spider
2014年4月17日在21:10



“ TimesTwo”中的构造函数不是默认构造函数。

–Lew Bloch
2014年9月3日下午0:09

我认为最好澄清最后一句话,指出这仅在此示例中,如果没有明确声明,则抽象类通常具有默认构造函数

– Vic Seedoubleyew
16年8月11日在14:24

与NOTE和Vic的注释类似,如果抽象类扩展了另一个没有默认构造函数的类,则抽象类必须具有一个构造函数,该构造函数调用要扩展的类的非默认构造函数。

–安迪·皇家(Andy Royal)
17年11月1日在15:13



#2 楼

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


要执行一些
初始化(对
抽象的字段类)实际上是在子类实例化之前发生的。
您已经在抽象类中定义了final字段,但没有
在声明中初始化它们
自己;在这种情况下,您必须具有
构造函数来初始化这些字段


请注意:


您可以定义多个
构造函数(具有不同的
参数)
您可以(应该?)定义所有受保护的
构造函数(使它们
毫无意义地公开)
您的子类构造函数可以
调用抽象类的一个构造函数
;它甚至可能必须调用它
(如果抽象类中没有no-arg构造函数


无论如何,请不要忘记,如果您没有t定义一个构造函数,然后编译器将自动为您生成一个(该构造函数是公共的,没有参数,并且不执行任何操作)。

#3 楼

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

#4 楼

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

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

注意:非抽象类不能具有抽象方法,但是抽象类可以具有非抽象方法。原因类似于构造函数,原因是可以调用super()来代替自动调用。此外,没有什么像抽象构造函数那样,因为它根本没有任何意义。

评论


关于说...的说明...抽象类的构造函数是自动调用的...这仅对抽象类的默认构造函数成立,其他的必须通过super(args)显式调用。

–antiplex
13年8月14日在12:10

非默认构造函数可以自动调用,前提是它们是无参数的构造函数。因此,不仅默认构造函数如此。

–Lew Bloch
2014年9月3日,0:11

#5 楼

它不仅可以,而且总是可以。如果不指定一个,则它具有默认的no arg构造函数,就像其他任何类一样。实际上,如果未指定一个,则所有类(包括嵌套类和匿名类)都将获得默认构造函数(对于匿名类,无法指定一个,因此您将始终获得默认构造函数)。

Calendar类是具有构造函数的抽象类的一个很好的例子。您可以通过调用Calendar.getInstance()获得Calendar对象,但它也具有受保护的构造方法。其构造函数受到保护的原因是,仅其子类可以调用它们(或同一包中的类,但由于它是抽象的,因此不适用)。 GregorianCalendar是扩展Calendar的类的示例。

#6 楼

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

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

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

#7 楼

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

#8 楼

尽管有很多好的答案,但我还是要给我2美分。

构造函数无法建立对象。它用于初始化对象。

是的,Abstract类始终具有构造函数。如果您未定义自己的构造函数,则编译器将为Abstract类提供默认的构造函数。
以上对所有类(嵌套,抽象,匿名等)均适用。

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

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()。如果您不显式调用super(),则Java会为您执行此操作。
下面的代码将无法编译:

public class Imp extends Abs{

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


您必须像使用它下例:

public class Imp extends Abs{

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


评论


构造函数不构建对象。它用于初始化字段。

–Optimus
18/12/7在11:22

#9 楼

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

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

参考文献:本文

#10 楼

请考虑以下问题:

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;
    }
}


超类是抽象的,并且具有构造函数。

评论


我知道这是一个过时的帖子,但是此代码段无法编译。 TimesTwo子类应实现非默认构造函数。

–MikeL
13年5月11日在11:37

这是一个编译错误。TimesTwo必须实现调用超级构造函数才能实现该抽象类。

– V. Sambor
16年5月5日在13:19

此代码将无法编译,因为您在Product类中没有默认构造函数,而TimesTwo具有默认构造函数。 TimesTwo的默认构造函数将使用super()调用Product类的默认构造函数,这将导致编译错误。

– Harshil
17年9月6日在12:12



#11 楼

如此处的javafuns所述,这是一个示例:

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
   }
}


评论


从geekinterview.com/question_details/77988中剪切并粘贴。窃并不酷。

– Cameron Skinner
13年8月28日在3:19

#12 楼

在一个具体的类中,为具体类型Fnord构造函数的声明有效地暴露了两件事:


一种方法,通过该方法代码可以请求创建Fnord的实例
A正在构造的Fnord派生类型的实例可以请求初始化所有基类功能的方法。

也许应该有一种方法可以分别控制这两种能力,对于每种具体类型,一个定义将同时启用两者。尽管第一个功能对抽象类没有意义,但是第二个功能对抽象类也和其他任何类一样有意义,因此声明它同样必要和有用。

#13 楼

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

// 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();
    }

}


这是上面代码的输出,

调用的基本构造方法
/>派生的构造函数称为

引用:
在此处输入链接描述

#14 楼

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

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

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()); 
    } 
}


所以我想您已经找到答案了。

#15 楼

尽管抽象类无法实例化,但可以具有构造函数。但是在抽象类中定义的构造函数可用于实例化此抽象类的具体类。检查JLS:


如果尝试使用类实例创建表达式创建抽象类的实例,则是编译时错误。

可以实例化本身不是抽象的抽象类的子类,
导致执行
抽象类的构造函数,并因此执行字段初始化程序
/>,例如该类的变量。


#16 楼

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

相反,接口确实仅包含常量变量,意味着它们已经被初始化。因此,接口不需要构造函数。

#17 楼

为了实现构造函数链接,抽象类将具有一个构造函数。
编译器将Super()语句保留在子类构造函数内,该子类构造函数将调用超类构造函数。如果没有抽象类的构造函数,则将违反Java规则,因此无法实现构造函数链接。

#18 楼

是的,抽象类可以具有构造函数。您可以在抽象类中重载任意数量的构造方法。这些承包商可用于初始化扩展Abstract类的对象的初始状态。众所周知,我们不能创建Abstract类的对象,因为对象是由“ new”关键字创建的,而不是由构造方法创建的...它们仅用于初始化子类Objects的状态。

#19 楼

是的,可以肯定地,您可以添加一个,如在Abstract类变量的初始化中已经提到的那样。
但是,如果您未显式声明一个,则它反而有一个隐式构造函数供“构造函数链接”使用。

#20 楼

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

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;
 }
}


#21 楼

包Test1;

公共类AbstractClassConstructor {

public AbstractClassConstructor() {

}

    public static void main(String args[]) {
       Demo obj = new Test("Test of code has started");
       obj.test1();
    }


}

abstract class Demo{
    protected final String demoValue;

    public Demo(String testName){
        this.demoValue = testName;
    }

    public abstract boolean test1();
}

class Test extends Demo{

    public Test(String name){
        super(name);
    }

    @Override
    public boolean test1() {
       System.out.println( this.demoValue + " Demo test started");
       return true;
    }

}


#22 楼

是的,就像其他班级一样。它可以具有构造函数,并且在为基类创建对象之后调用它。

评论


它不同于其他任何课程。不能像其他任何类一样实例化它。

–阿斯拉·吉夫里(Aslam Jiffry)
15年7月6日在6:38