ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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


r
rimsky

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

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

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

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


@Jonathon:为了回答所提出的问题而增加复杂性并没有获得真正的好处。如果问题是关于范围的,那么,是的,对比这三种有用的可能性是有意义的。
我认为 Jonathon 想说的是抽象类上的公共构造函数没有任何意义,因为您不能直接实例化抽象类(只能通过本身未标记为抽象的派生类型实例化)。
“TimesTwo”中的构造函数不是默认构造函数。
我认为最好澄清最后一句话,说明这仅在此示例中,如果没有明确声明,通常抽象类具有默认构造函数
与 NOTE 和 Vic 的评论类似,如果抽象类 extends 是另一个没有默认构造函数的类,则该抽象类必须有一个构造函数,该构造函数调用它所扩展类的非默认构造函数。
j
jfpoilpret

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

您想在子类的实例化实际发生之前执行一些初始化(对抽象类的字段)

您已经在抽象类中定义了 final 字段,但您没有在声明本身中初始化它们;在这种情况下,您必须有一个构造函数来初始化这些字段

注意:

您可以定义多个构造函数(具有不同的参数)

您可以(应该?)定义所有受保护的构造函数(无论如何,将它们公开毫无意义)

您的子类构造函数可以调用抽象类的一个构造函数;它甚至可能必须调用它(如果抽象类中没有无参数构造函数)

无论如何,不要忘记,如果你不定义构造函数,那么编译器会自动为你生成一个(这个是公共的,没有参数,什么也不做)。


使它们受到保护的奖励。它增加了一点完整性。
L
Lawrence Dol

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


Y
Yoon5oo

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

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

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

注意:非抽象类不能有抽象方法,但抽象类可以有非抽象方法。 Reason 类似于构造函数,不同之处在于我们可以调用 super(),而不是自动调用。此外,没有什么比抽象构造函数更好的了,因为它根本没有意义。


注意说......抽象类的构造函数被自动调用......这仅适用于抽象类的默认构造函数,其他必须通过super(args)显式调用。
可以自动调用非默认构造函数,前提是它们是无参数构造函数。所以它不仅适用于默认构造函数。
M
MattC

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

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


Y
Yoon5oo

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

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

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


J
Jacob

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


R
Raj Baral

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

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

参考:This Article


Y
Yoon5oo

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

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

是的,抽象类总是有一个构造函数。如果你没有定义自己的构造函数,编译器会给抽象类一个默认的构造函数。以上适用于所有类 - 嵌套、抽象、匿名等。

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

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

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

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

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

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

所以我想你得到了答案。


B
Brad Larson

如 javafuns here 所述,这是一个示例:

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 剪切和粘贴。抄袭并不酷。
s
supercat

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

一种代码可以请求创建 Fnord 实例的方法

一种从 Fnord 派生的类型的实例(正在构建中)可以请求初始化所有基类特性的方法。

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


c
chamzz.dot

是的。并且在创建继承类的实例时调用抽象类的构造函数。例如,以下是一个有效的 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();
    }

}

这是上面代码的输出,

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

参考:enter link description here


S
S.Lott

考虑一下:

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 应该实现非默认构造函数。
这是一个编译错误... TimesTwo 必须实现调用超级构造函数才能实现该抽象类...。
此代码不会编译,因为您在 Product 类中没有默认构造函数,而您的 TimesTwo 具有默认构造函数。 TimesTwo 的默认构造函数会使用 super() 调用 Product 类的默认构造函数,这会导致编译错误。
抽象类需要一个默认的无参数构造函数,或者它的具体类应该调用 super(val),即使用 int 参数调用父类的参数化构造函数。
K
Kedar Parikh

是的,你当然可以添加一个,正如已经提到的抽象类变量的初始化。但是,如果您没有明确声明一个,它无论如何都有一个隐式构造函数供“构造函数链接”工作。


a
akhil_mittal

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

如果尝试使用类实例创建表达式创建抽象类的实例,则会出现编译时错误。可以实例化本身不是抽象的抽象类的子类,从而导致执行抽象类的构造函数,并因此执行该类的实例变量的字段初始值设定项。


Y
Yoon5oo

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

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


Y
Yoon5oo

为了实现构造函数链接,抽象类会有一个构造函数。编译器将 Super() 语句保留在子类构造函数中,它将调用超类构造函数。如果抽象类没有构造函数,则违反了 java 规则,我们无法实现构造函数链接。


Y
Yoon5oo

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


k
karto

类中构造函数的目的是用于初始化字段,而不是“构建对象”。当你试图创建一个抽象超类的新实例时,编译器会给你一个错误。但是,我们可以继承一个抽象类 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;
 }
}

e
exhuma
package Test1;

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

S
Sandeep

是的..它就像任何其他课程一样。它可以有一个构造函数,并在为基类创建对象后调用它。


它不像任何其他类。它不能像任何其他类一样被实例化。