在Java中模拟构造函数重写?

在Java中模拟构造函数重写?,java,inheritance,constructor,initialization,Java,Inheritance,Constructor,Initialization,有好几次我认为在Java中有可重写的构造函数会很好 Overridable(可重写)表示构造逻辑可以在降序类中被重写和/或扩展,其方式与重写普通方法相同,即能够在子方法之后调用父方法 这个任务可以表述为有一个名为init的方法,该方法在构造时被调用,但只在堆栈的最后一个构造函数中调用 比如: 最明显的方法是写作 public static void main(String[] args) { new A().init(); new B().init(); n

有好几次我认为在Java中有可重写的构造函数会很好

Overridable(可重写)表示构造逻辑可以在降序类中被重写和/或扩展,其方式与重写普通方法相同,即能够在子方法之后调用父方法

这个任务可以表述为有一个名为init的方法,该方法在构造时被调用,但只在堆栈的最后一个构造函数中调用

比如:

最明显的方法是写作

public static void main(String[] args) {

      new A().init();
      new B().init();
      new C().init();

   }
但这并不保证init不会忘记调用

有可能吗

更新

在设计时还不知道哪个类是最后一个。可以预期,未来将开发类树

更新2

下面是在最后调用currentStage的反射和构造函数代码要求的解决方案:

public class InitializationOverride {

   public static class A {
      A() {
         System.out.println("Constructor of A");

         currentStage(A.class);
      }

      void currentStage(Class<?> cls) {
         if( cls == getClass() ) {
            init();
         }
      }

      void init() {
         System.out.println("Init of A");
      }
   }

   public static class B extends A {

      B() {
         System.out.println("Constructor of B");

         currentStage(B.class);
      }

      @Override
      void init() {
         System.out.println("Init of B");
      }
   }

   public static class C extends B {

      C() {
         System.out.println("Constructor of C");

         currentStage(C.class);
      }

      @Override
      void init() {
         System.out.println("Init of C");
      }
   }

   public static void main(String[] args) {

      new A(); // should print "Constructor of A, Init of A"
      new B(); // should print "Constructor of A, Constructor of B, Init of B"
      new C(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"

   }
可以编写更简单的吗?

在Java中,当实例化子类时,总是调用父类的默认构造函数,除非指定了任何其他构造函数。现在,如果需要为所有类执行公共代码,建议将其放入构造函数中。但是,如果您希望只在层次结构中的最后一个类中执行某个操作,那么a您可以将其写入最后一个构造函数本身,或者b写入初始化块,下面的示例演示了这一点:

public class Test extends Test2{

    public Test(){
        System.out.println("In test");
        System.out.println("Init last");
    }

    {
        System.out.println("Init");
    }

    public static void main(String[] args) {
        new Test();
    }
}

class Test2{
    public Test2(){
        System.out.println("In test 2");
    }
}
在Java中,当实例化子类时,除非指定了任何其他构造函数,否则总是调用父类的默认构造函数。现在,如果需要为所有类执行公共代码,建议将其放入构造函数中。但是,如果您希望只在层次结构中的最后一个类中执行某个操作,那么a您可以将其写入最后一个构造函数本身,或者b写入初始化块,下面的示例演示了这一点:

public class Test extends Test2{

    public Test(){
        System.out.println("In test");
        System.out.println("Init last");
    }

    {
        System.out.println("Init");
    }

    public static void main(String[] args) {
        new Test();
    }
}

class Test2{
    public Test2(){
        System.out.println("In test 2");
    }
}

只需像这样更改a类构造函数,每个对象init方法都将通过调用this.init来调用。您只需更改大多数上层类构造函数。因为在创建对象时,父类构造函数肯定会调用

public class Test {
    public static class A {

        public A() {

            this.init();
        }

        void init() {
            System.out.println("Called in A");
        }
    }

    public static class B extends A {

        @Override
        void init() {
            System.out.println("Called in B");
        }
    }

    public static class C extends B {

        @Override
        void init() {
            System.out.println("Called in C");
        }
    }

    public static void main(String[] args) {

        new A(); // should "Called in A" printed
        new B(); // should "Called in B" printed
        new C(); // should "Called in C" printed

    }
}

只需像这样更改a类构造函数,每个对象init方法都将通过调用this.init来调用。您只需更改大多数上层类构造函数。因为在创建对象时,父类构造函数肯定会调用

public class Test {
    public static class A {

        public A() {

            this.init();
        }

        void init() {
            System.out.println("Called in A");
        }
    }

    public static class B extends A {

        @Override
        void init() {
            System.out.println("Called in B");
        }
    }

    public static class C extends B {

        @Override
        void init() {
            System.out.println("Called in C");
        }
    }

    public static void main(String[] args) {

        new A(); // should "Called in A" printed
        new B(); // should "Called in B" printed
        new C(); // should "Called in C" printed

    }
}

为此使用super.init调用根父类init。

为此使用super.init调用根父类init。

构造函数不应调用可重写的方法。如果需要调用此类方法,更好的解决方案是保护构造函数并提供静态工厂方法:

public class InitializationOverride {

   public static class A {
      protected A() {
         System.out.println("Constructor of A");
      }

      public static A newInstance(){
        A a = new A();
        a.init();
        return a;
      }

      protected void init() {
         System.out.println("Init of A");
      }
   }

   public static class B extends A {

      protected B() {
         System.out.println("Constructor of B");
      }

      public static B newInstance(){
        B b = new B();
        b.init();
        return b;
      }

      @Override
      protected void init() {
         System.out.println("Init of B");
      }
   }

   public static class C extends B {

      protected C() {
         System.out.println("Constructor of C");
      }

      public static C newInstance(){
        C c = new C();
        c.init();
        return c;
      }

      @Override
      protected void init() {
         System.out.println("Init of C");
      }
   }

   public static void main(String[] args) {

      A.newInstance(); // should print "Constructor of A, Init of A"
      B.newInstance(); // should print "Constructor of A, Constructor of B, Init of B"
      C.newInstance(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"

   }
}
编辑 更多说明:这种解决方案既有好处,也有缺点。您应该为类提供一个契约,即在Javadoc中,扩展类的子类应该遵循这个对象创建标准。它还创建了更多的代码。利润是以这种方式创建的对象:

C obj = C.newInstance() 
…始终是完全初始化的,不需要记住调用init方法显式


请记住,它也是类“包构造函数不可用,但在同一个包构造函数内仍然可用”之外创建对象的唯一方法。受保护的方法在同一个包内可用。构造函数不应调用可重写的方法。如果需要调用此类方法,更好的解决方案是保护构造函数并提供静态工厂方法:

public class InitializationOverride {

   public static class A {
      protected A() {
         System.out.println("Constructor of A");
      }

      public static A newInstance(){
        A a = new A();
        a.init();
        return a;
      }

      protected void init() {
         System.out.println("Init of A");
      }
   }

   public static class B extends A {

      protected B() {
         System.out.println("Constructor of B");
      }

      public static B newInstance(){
        B b = new B();
        b.init();
        return b;
      }

      @Override
      protected void init() {
         System.out.println("Init of B");
      }
   }

   public static class C extends B {

      protected C() {
         System.out.println("Constructor of C");
      }

      public static C newInstance(){
        C c = new C();
        c.init();
        return c;
      }

      @Override
      protected void init() {
         System.out.println("Init of C");
      }
   }

   public static void main(String[] args) {

      A.newInstance(); // should print "Constructor of A, Init of A"
      B.newInstance(); // should print "Constructor of A, Constructor of B, Init of B"
      C.newInstance(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"

   }
}
编辑 更多说明:这种解决方案既有好处,也有缺点。您应该为类提供一个契约,即在Javadoc中,扩展类的子类应该遵循这个对象创建标准。它还创建了更多的代码。利润是以这种方式创建的对象:

C obj = C.newInstance() 
…始终是完全初始化的,不需要记住调用init方法显式


记住,它也是在类“包构造函数不可用”之外创建对象的唯一方法,但是在同一个包中构造函数仍然可用受保护的方法在同一个包中可用

您没有说明为什么您认为构造函数应该调用这些方法。在C构造函数中直接调用init有什么问题?放置super.init有什么问题;在每个重写方法中?@defaultlocale如果我将init放在C构造函数中,则在构造A和B时不会调用它。将super.init放在任何位置都没有问题,但这会有什么帮助?重写构造函数中调用的方法是可能的,但它被认为是一个糟糕的设计,可能会导致一些问题,看这个问题的细节,现在它变得复杂了。你能告诉我们这种设计背后的原因吗?此外,这个问题还包含一些建议:您没有说明为什么您认为构造函数应该调用这些方法
在C构造函数中直接调用init有问题吗?放置super.init有什么问题;在每个重写方法中?@defaultlocale如果我将init放在C构造函数中,则在构造A和B时不会调用它。将super.init放在任何位置都没有问题,但这会有什么帮助?重写构造函数中调用的方法是可能的,但它被认为是一个糟糕的设计,可能会导致一些问题,看这个问题的细节,现在它变得复杂了。你能告诉我们这种设计背后的原因吗?此外,这个问题还包含一些建议:您可以编写整个示例吗?我不明白,为什么它会工作?对不起,你是对的,我的代码是个坏例子。请看我的更新。根据Joshua的Bloch Effective Java中的第17项,您的示例设计得很差:类必须遵守更多的限制才能允许继承。构造函数不能直接或间接调用可重写的方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前被调用。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法的行为将不符合预期。Dims如果您尚未决定哪个类将是顶级父类,则很难实现此目标,我同意您的观点“构造函数不得调用重写方法”,但OP已经在所有类中声明了公共方法,所以我并没有想过要改变他的所有设计,你们能写出整个例子吗?我不明白,为什么它会工作?对不起,你是对的,我的代码是个坏例子。请看我的更新。根据Joshua的Bloch Effective Java中的第17项,您的示例设计得很差:类必须遵守更多的限制才能允许继承。构造函数不能直接或间接调用可重写的方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前被调用。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法的行为将不符合预期。Dims如果您尚未决定哪个类将是顶级父类,则很难实现此目标,我同意您的观点“构造函数不得调用重写方法”,但OP已经在所有类中声明了公共方法,所以我并没有想到要改变他的所有设计