Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.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_Inheritance - Fatal编程技术网

Java继承的行为不符合预期

Java继承的行为不符合预期,java,inheritance,Java,Inheritance,需要以下上下文:这种编码方式的目的是避免if-else语句和instanceof;这总是个坏主意 我有3门课,签名如下: abstract class A {} class B extends A {} class C extends A {} 然后我有另一个具有以下结构的类: class MyClass { private final A model; public MyClass(A m) { this.model = m; } publ

需要以下上下文:这种编码方式的目的是避免if-else语句和instanceof;这总是个坏主意

我有3门课,签名如下:

abstract class A {}
class B extends A {}
class C extends A {}
然后我有另一个具有以下结构的类:

class MyClass {
    private final A model;

    public MyClass(A m) {
        this.model = m;
    }

    public void doSomething() {
        System.out.println(this.model instanceof C); //TRUE!!
        execute(this.model);
    }

    private void execute(A m) {
        System.out.println("noo");
    }

    private void execute(C m) {
        System.out.println("yay");
    }
}
最后是我的主要内容:

public static void main(String... args) {
    C mod = new C();
    MyClass myClass = new MyClass(mod);
    myClass.doSomething();
}

现在问题来了,;executeC方法永远不会被执行,它总是executeA方法。我怎样才能解决这个问题?我无法将executeA方法的签名更改为executeB,因为这会导致一个错误,即java无法在MyClassdoSomething解析方法executeA。

方法重载在编译时解析。在编译时,m的类型是A,因此executeA m被执行

此外,私有方法是不可重写的


解决方案是使用@OliverCharlesworth建议的访问者模式。

方法重载在编译时解决。在编译时,m的类型是A,因此executeA m被执行

此外,私有方法是不可重写的


解决方案是使用@OliverCharlesworth建议的访问者模式。

您的代码说明了对象的静态类型和动态类型之间的区别。静态类型是编译器已知的类型;动态类型是运行时实际存在的类型

模型字段的静态类型为:

也就是说,编译器知道一个模型本身或它的一些实现将被分配给该模型。编译器不知道其他任何东西,因此在选择executeA m和executeC m时,它唯一的选择是executeA m。该方法根据对象的静态类型进行解析

另一方面,instanceof理解动态类型。它可以判断模型被设置为C,因此在打印输出中报告真值

您可以通过向a添加一个方法并在B和C中重写它来解决此问题,以路由到正确的执行:

请注意,这两种实现都调用

back.execute(this);
但是,B中的实现的类型是B,C中的实现的类型是C,因此调用被路由到MyClass的execute方法的不同重载

我无法将executeA方法的签名更改为executeB


还要注意,现在您也可以而且应该这样做,因为回调是根据对象的类型执行到正确的重载的。

您的代码说明了对象的静态类型和动态类型之间的区别。静态类型是编译器已知的类型;动态类型是运行时实际存在的类型

模型字段的静态类型为:

也就是说,编译器知道一个模型本身或它的一些实现将被分配给该模型。编译器不知道其他任何东西,因此在选择executeA m和executeC m时,它唯一的选择是executeA m。该方法根据对象的静态类型进行解析

另一方面,instanceof理解动态类型。它可以判断模型被设置为C,因此在打印输出中报告真值

您可以通过向a添加一个方法并在B和C中重写它来解决此问题,以路由到正确的执行:

请注意,这两种实现都调用

back.execute(this);
但是,B中的实现的类型是B,C中的实现的类型是C,因此调用被路由到MyClass的execute方法的不同重载

我无法将executeA方法的签名更改为executeB


还请注意,现在您也可以而且应该这样做,因为回调是根据这种类型执行到正确重载的。

方法重载是编译时多态性。因此,为了调用方法executeC,您需要将模型定义为类C。 最好在类A中定义方法execute并在子类中重写它

abstract class A {
    abstract void execute();
}
class B extends A {
    public void execute(){};
}
class C extends A {
    public void execute(){};
}
然后:

class MyClass {
    private final A model;

public void doSomething() {
    model.execute();
}

使用多态性来避免if-else语句和instanceof-checking方法重载的更好方法是编译时多态性。因此,为了调用方法executeC,您需要将模型定义为类C。 最好在类A中定义方法execute并在子类中重写它

abstract class A {
    abstract void execute();
}
class B extends A {
    public void execute(){};
}
class C extends A {
    public void execute(){};
}
然后:

class MyClass {
    private final A model;

public void doSomething() {
    model.execute();
}

使用多态性可以更好地避免if-else语句和instanceof-checking

您在构造函数中将类型C的对象作为类型A的对象发送,您已经完成了向上转换,并将其分配给类型A的引用,这将导致只调用executeA方法。您可以检查该对象是否是C的实例,具体取决于对于结果,调用所需的方法。你可以这样做

    public void doSomething(){
        System.out.println(model instanceof C);
        if (model instanceof C) execute((C)model);
        else
            execute(model);
    }

您正在将C类型的对象作为构造函数中的A类型对象发送,您已经完成了向上转换,并将其分配给A类型的引用,这将导致只调用executeA方法。您可以检查该对象是否是C的实例,并根据结果调用所需的方法。你可以这样做

    public void doSomething(){
        System.out.println(model instanceof C);
        if (model instanceof C) execute((C)model);
        else
            execute(model);
    }
这个问题可以在某种程度上解决
ost通过.A model->executeA,有什么问题吗?@OliverCharlesworth还没有听说过这个问题;这看起来确实很有趣。这可以通过.A model->executeA来解决,有什么问题吗?@OliverCharlesworth还没听说过这个问题;这看起来确实很有趣。@OliverCharlesworth同意,访问者模式就是答案,正如你所建议的。接受另一个答案是因为它更详细,而你的答案也是正确的。@OliverCharlesworth同意,访问者模式就是答案,正如你所建议的。接受另一个答案是因为它更详细,但是你的也是正确的。Never use instanceofI不会说Never,但我同意有更好的方法:Never use instanceofI不会说Never,但我同意有更好的方法: