2016-03-20 187 views
1

我想在Java中实现CAS类似的东西,但我正在努力处理类型和方法选择。奇怪的类型行为

当我添加这两个亚型时,一切都很好。 当我添加一个超类型的子类型发生无限递归。 当超类型再次罚款,当我添加一个超类型的子类型相同的递归再次发生。

有人可以解释这里发生了什么,我做错了什么?

public class MathMain{ 
    public static void main(String[] args){ 
     Constant constant = new Constant(1); 
     constant.add(constant); 
     MathObject mathObject = (MathObject)constant; 
     constant.add(mathObject); 
     constant.add((Constant)mathObject); 
     mathObject.add(constant); 
    } 
} 


public abstract class MathObject{ 
    public abstract MathObject add(MathObject addend); 
    public abstract MathObject substract(MathObject subtrahend); 
} 


public class Constant extends MathObject{ 
    public final double c; 

    public Constant(double c){ 
     this.c = c; 
    } 

    public MathObject add(MathObject that){ 
     return that.add((Constant)this); 
    } 

    public MathObject substract(MathObject that){ 
     return that.substract((Constant)this); 
    } 

    public Constant add(Constant addend){ 
     return new Constant(c + addend.c); 
    } 

    public Constant substract(Constant subtrahend){ 
     return new Constant(c - subtrahend.c); 
    } 
} 

回答

2

要记住的重要一点是,方法重载是在编译时确定的,而方法覆盖在运行时确定。

mathObject.add(constant) 

选择了MathObject add(MathObject addend)方法,该方法可用于MathObject唯一add方法。

在运行时,由于mathObject运行时类型Constant,的ConstantMathObject add(MathObject that)被执行,并且它调用that.add((Constant)this)。由于that的类型为MathObject,所以再次选择MathObject add(MathObject addend),这意味着您的方法正在调用自己的无限递归。

唯一的办法你Constant add(Constant addend)将由that.add((Constant)this)表达被称为是如果that编译时类型是Constant,因为MathObject不具有add方法接受一个Constant说法。

现在,对于工作情况:

constant.add(constant) 
constant.add((Constant)mathObject) 

直接两个呼叫Constant add(Constant addend),由于constant编译类型是Constant并且选择与所述多个特定的参数类型的方法。

我不知道这是一个很好的解决方案,只有一种解释,并得到了无限递归是检查参数的类型:

public MathObject add(MathObject that){ 
    if (that instanceof Constant) 
     return add((Constant) that); 
    else 
     that.add((Constant)this); // note that the casting here only makes 
            // sense if MathObject has an add method 
            // that takes a Constant. otherwise is makes 
            // no difference 
} 
+0

感谢您指出这个监督:) 我我想到了克隆被调用者并回调调用者的解决方法,但是如何为需要保留原始指针的对象执行此操作,例如一个变量? –

+0

为什么Java没有意识到'MathObject add(MathObject)'return that.add(this)'这个实际上是一个Constant而不是声明的MathObject,即使这个方法显然位于Constant类而不是MathObject类?顺便说一下,上述解决方法由于某种原因不起作用。 –

+0

@ S.Klumpers参数'that'可以是'MathObject'的任何子类。并且由于基础'MathObject'没有'add(常量加数)'方法,所以在编写'that.add(this)'时,它不能调用该方法,即使''that'的运行时类型是'Constant'。 – Eran