在抽象类的构造函数中使用抽象的init()函数 [英] Using abstract init() function in abstract class's constructor

查看:201
本文介绍了在抽象类的构造函数中使用抽象的init()函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的事情:

  public abstract class Menu {
public Menu(){
init();
}

protected abstract void init();

protected void addMenuItem(MenuItem menuItem){
// some code ...
}
}

public class ConcreteMenu extends Menu {
protected void init(){
addMenuItem(new MenuItem(ITEM1));
addMenuItem(new MenuItem(ITEM2));
// ....
}
}

//代码中的某处
菜单menu1 = new ConcreteMenu();

正如您所见,超类的init方法是抽象的,并且在创建对象后由构造函数自动调用。 / p>

我很好奇我是否可以遇到类似这样的代码的某些问题,当我需要创建一些这样的结构时,其结构不会被改变时间。



会有更好的方法吗?它适用于Java,但是它可以在C ++和ActionScript中使用吗?



感谢您的回答。

解决方案

不要从构造函数中发现过多的方法。



来自 Effective Java 2nd Edition的引用,第17项:设计和继承文档,或者禁止它


类允许继承时必须遵守一些限制。 构造函数不得直接或间接调用可覆盖的方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行。


这是一个示例来说明:

  public class ConstructorCallsOverride {
public static void main(String [] args){
abstract class Base {
Base(){overrideMe(); }
abstract void overrideMe();
}
class Child extends Base {
final int x;
Child(int x){this.x = x; }
@Override void overrideMe(){
System.out.println(x);
}
}
新孩子(42); //打印0
}
}

这里,当 Base 构造函数调用 overrideMe Child 尚未完成初始化 final int x ,该方法获取错误的值。这几乎肯定会导致错误和错误。



相关问题





另请参阅




I have something like this:

    public abstract class Menu {
     public Menu() {
      init();
     }

     protected abstract void init();

     protected void addMenuItem(MenuItem menuItem) {
      // some code...
     }
    }

    public class ConcreteMenu extends Menu {
     protected void init() {
      addMenuItem(new MenuItem("ITEM1"));
      addMenuItem(new MenuItem("ITEM2"));
      // ....
     }
    }

//Somewhere in code
Menu menu1 = new ConcreteMenu();

As you can see superclass's init method is abstract and is called by constructor automatically after object is created.

I'm curious if i can run into some sort of problems with code like this, when i need to create some object of this kind whose structure wont't be changed in time.

Would be any approach better? It works in Java, but will it work in C++ and possibly ActionScript?

Thank you for answer.

解决方案

DO NOT INVOKE OVERRIDEABLE METHODS FROM THE CONSTRUCTOR.

A quote from Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:

There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will be invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.

Here's an example to illustrate:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

Here, when Base constructor calls overrideMe, Child has not finished initializing the final int x, and the method gets the wrong value. This will almost certainly lead to bugs and errors.

Related questions

See also

这篇关于在抽象类的构造函数中使用抽象的init()函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆