Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么';构造函数中的可重写方法调用有什么问题?_Java_Oop_Inheritance_Constructor_Overriding - Fatal编程技术网

Java 什么';构造函数中的可重写方法调用有什么问题?

Java 什么';构造函数中的可重写方法调用有什么问题?,java,oop,inheritance,constructor,overriding,Java,Oop,Inheritance,Constructor,Overriding,我有一个Wicket page类,它根据抽象方法的结果设置页面标题 public abstract class BasicPage extends WebPage { public BasicPage() { add(new Label("title", getTitle())); } protected abstract String getTitle(); } NetBeans用消息“构造函数中可重写的方法调用”警告我,但它有什么错呢?我能想象

我有一个Wicket page类,它根据抽象方法的结果设置页面标题

public abstract class BasicPage extends WebPage {

    public BasicPage() {
        add(new Label("title", getTitle()));
    }

    protected abstract String getTitle();

}

NetBeans用消息“构造函数中可重写的方法调用”警告我,但它有什么错呢?我能想象的唯一替代方法是将其他抽象方法的结果传递给子类中的超级构造函数。但是,对于许多参数来说,这可能很难理解。

如果在构造函数中调用子类重写的方法,这意味着如果在构造函数和方法之间按逻辑划分初始化,则不太可能引用尚不存在的变量


查看此示例链接

如果在构造函数中调用子类重写的方法,这意味着如果在构造函数和方法之间按逻辑划分初始化,则不太可能引用尚不存在的变量


看看这个示例链接

调用构造函数中的可重写方法允许子类破坏代码,因此您不能保证它还能工作。这就是为什么你会收到警告

在您的示例中,如果子类重写
getTitle()
并返回null,会发生什么情况


若要“修复”此问题,可以使用构造函数而不是构造函数,这是对象实例关联的常见模式。

调用构造函数中的可重写方法允许子类破坏代码,因此您无法保证它继续工作。这就是为什么你会收到警告

在您的示例中,如果子类重写
getTitle()
并返回null,会发生什么情况

若要“修复”此问题,可以使用一个而不是构造函数,这是对象实例关联的一种常见模式。

关于从构造函数调用可重写方法 简单地说,这是错误的,因为它不必要地为许多bug打开了可能性。调用
@Override
时,对象的状态可能不一致和/或不完整

引用有效Java第二版第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);
            }
        }
        new Child(42); // prints "0"
    }
}
这里,当
Base
构造函数调用
overrideMe
时,
子项
尚未完成初始化
最终整数x
,并且该方法获取了错误的值。这几乎肯定会导致bug和错误

相关问题
另见

关于多参数对象构造 具有许多参数的构造函数可能导致可读性差,并且存在更好的替代方法

这是一个来自java第二版的引用,项目2:在遇到许多构造函数参数时考虑构造器模式:

传统上,程序员使用伸缩构造函数模式,在这种模式中,您只提供一个具有所需参数的构造函数,另一个具有单个可选参数,第三个具有两个可选参数,依此类推

伸缩构造函数模式基本上是这样的:

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}
现在,您可以执行以下任一操作:

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);
但是,您当前无法仅设置
名称
可调整
,并将
级别保留为默认值。您可以提供更多的构造函数重载,但很明显,随着参数数量的增加,这个数量会急剧增加,甚至可能有多个
boolean
int
参数,这会让事情变得一团糟

正如你所看到的,这不是一个令人愉快的模式,使用起来更不愉快(这里“真”是什么意思?13是什么?)

Bloch建议使用builder模式,这将允许您编写如下内容:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();
请注意,现在这些参数已命名,您可以按任意顺序设置它们,并且可以跳过希望保留为默认值的参数。这当然比伸缩构造函数好得多,特别是当有大量属于许多相同类型的参数时

另见
  • < LI> java第二版,第2项:在遇到许多构造函数参数时考虑构造器模式()
相关问题
从构造函数调用可重写方法 简单地说,这是错误的,因为它不必要地为许多bug打开了可能性。调用
@Override
时,对象的状态可能不一致和/或不完整

引用有效Java第二版第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);
            }
        }
        new Child(42); // prints "0"
    }
}
这里,当
Base
构造函数调用
overrideMe
时,
子项
尚未完成初始化
最终整数x
,并且该方法获取了错误的值。这
Constructing A
Using C
Constructing C
class A {

    protected int minWeeklySalary;
    protected int maxWeeklySalary;

    protected static final int MIN = 1000;
    protected static final int MAX = 2000;

    public A() {
        setSalaryRange();
    }

    protected void setSalaryRange() {
        throw new RuntimeException("not implemented");
    }

    public void pr() {
        System.out.println("minWeeklySalary: " + minWeeklySalary);
        System.out.println("maxWeeklySalary: " + maxWeeklySalary);
    }
}

class B extends A {

    private int factor = 1;

    public B(int _factor) {
        this.factor = _factor;
    }

    @Override
    protected void setSalaryRange() {
        this.minWeeklySalary = MIN * this.factor;
        this.maxWeeklySalary = MAX * this.factor;
    }
}

public static void main(String[] args) {
    B b = new B(2);
    b.pr();
}
public abstract class BasicPage extends WebPage {

    public BasicPage() {
    }

    @Override
    public void onInitialize() {
        add(new Label("title", getTitle()));
    }

    protected abstract String getTitle();
}