【问题标题】:Can an abstract class have a constructor?抽象类可以有构造函数吗?
【发布时间】:2010-09-20 14:43:24
【问题描述】:

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

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

【问题讨论】:

    标签: java constructor abstract-class


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

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

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

    【讨论】:

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

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

    • 你想执行一些 初始化(到的字段 抽象类)之前 实际上是子类的实例化 发生
    • 您已在 抽象类,但你没有 在声明中初始化它们 本身;在这种情况下,你必须有 初始化这些的构造函数 字段

    注意:

    • 您可以定义多个 构造函数(不同的 论据)
    • 你可以(应该?)定义你所有的 构造函数受保护(使它们 无论如何,public 毫无意义)
    • 您的子类构造函数可以 调用抽象的一个构造函数 班级;它甚至可能不得不调用它 (如果没有无参数构造函数 在抽象类中)

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

    【讨论】:

    • 保护它们的奖励。它增加了很好的完整性。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      【讨论】:

      • 注意说...抽象类的构造函数被自动调用...这仅适用于抽象类的默认构造函数,其他人必须这样做通过 super(args) 显式调用。
      • 可以自动调用非默认构造函数,前提是它们是无参数构造函数。所以它不仅适用于默认构造函数。
      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

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

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

            虽然有很多好的答案,但我还是愿意付出我的 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");
            }
            }
            

            【讨论】:

            • 构造函数不构建对象。它用于初始化字段
            【解决方案9】:

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

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

            参考:This Article

            【讨论】:

              【解决方案10】:

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

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

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

              所以我想你得到了答案。

              【讨论】:

                【解决方案11】:

                考虑一下:

                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 类的默认构造函数,会导致编译错误。
                【解决方案12】:

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

                【讨论】:

                【解决方案13】:

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

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

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

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

                【讨论】:

                  【解决方案14】:

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

                  【讨论】:

                    【解决方案15】:

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

                    【讨论】:

                      【解决方案16】:

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

                      如果尝试使用类实例创建来创建抽象类的实例,则会出现编译时错误 表达

                      本身不是抽象的抽象类的子类可能是 实例化,导致执行构造函数 抽象类,因此,字段初始值设定项的执行 例如该类的变量。

                      【讨论】:

                        【解决方案17】:

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

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

                        【讨论】:

                          【解决方案18】:

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

                          【讨论】:

                            【解决方案19】:

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

                            【讨论】:

                              【解决方案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】:
                                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;
                                    }
                                   
                                }
                                

                                【讨论】:

                                  【解决方案22】:

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

                                  【讨论】:

                                  • it' 不像任何其他类。它不能像任何其他类一样被实例化。
                                  猜你喜欢
                                  • 1970-01-01
                                  • 2016-05-05
                                  • 1970-01-01
                                  • 2013-11-25
                                  • 1970-01-01
                                  • 2018-09-03
                                  • 2022-01-22
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多