代码之家  ›  专栏  ›  技术社区  ›  Lie Ryan Bryan

Java中的部分重写(或重载时的动态重写)

  •  2
  • Lie Ryan Bryan  · 技术社区  · 14 年前

    如果我有一个父子关系,它定义了如下的method.foo():

    class Parent {
      public void foo(Parent arg) {
        System.out.println("foo in Function");
      }
    }
    class Child extends Parent {
      public void foo(Child arg) {
        System.out.println("foo in ChildFunction");
      }  
    }
    

    当我这样称呼他们时:

      Child f = new Child();
      Parent g = f;
      f.foo(new Parent());
      f.foo(new Child());  
      g.foo(new Parent());
      g.foo(new Child());
    

    输出为:

    foo in Parent
    foo in Child
    foo in Parent
    foo in Parent
    

    但是,我想要这个输出:

    foo in Parent
    foo in Child
    foo in Parent
    foo in Child
    

    我有一个扩展父类的子类。在子类中,我希望“部分重写”父类的 foo() ,也就是说,如果 arg 的类型是child,然后是child 英尺() 被调用而不是父的 英尺() .

    我打电话的时候没问题 f.foo(...) 作为一个孩子;但是如果我从它的父别名中引用它,比如 g.foo(...) 那么父母的 foo(..) 不分类型地调用 精氨酸 .

    据我所知,我所预期的不会发生,因为Java中的方法重载是早期绑定(即在编译时静态解析),而方法重写是后期绑定(即在编译时动态解析),并且因为我定义了一个具有不同技术的函数。ent type,我在技术上用一个不同的定义重载父类定义,而不是重写它。但我想做的是在概念上“部分覆盖”什么时候。 英尺() 的参数是 英尺() 的论点。

    我知道我可以定义bucket override foo(Parent arg) 在检查arg的实际类型是父类型还是子类型并正确传递它的child中,但是如果我有20个子类型,那将是类型不安全代码的大量重复。

    在我的实际代码中,parent是一个名为“function”的抽象类,它只是抛出 NotImplementedException() . 子项包括“多项式”、“对数”等,foo()包括child.add(child)、child.intersectionswith(child)等。不是child.foo(otherchild)的所有组合都是可解的,事实上甚至不是所有child.foo(child)都是可解的。所以我最好还是定义所有未定义的东西(即抛出notimplementedexception),然后只定义那些可以定义的东西。

    所以问题是:有什么方法可以只覆盖父对象的foo()部分吗?还是有更好的方法做我想做的事?

    编辑 :

    @蔡司:如果我使用双重调度,就像这样:

    class Parent {
      public void foo(Parent arg) {
        System.out.println("foo in Parent");
      }
    }
    class Child extends Parent {
      public void foo(Parent arg) {
        System.out.println("foo in Child(Parent)");
        arg.foo(this);
      }
      public void foo(Child arg) {
        System.out.println("foo in Child(Child)");
      }
    }
    

    我得到了无限递归:

    (stack): 
    StackOverflowError: ...
    ...
        at sketch_apr25a$Child.foo(sketch_apr25a.java:35)
    ...
    (output):
    ...
    foo in Child(Parent)
    ...
    

    执行时 g.foo(new Child()); . 剩下的似乎很好,因为输出是:

    foo in Child(Parent)
    foo in Parent
    
    foo in Child(Child)
    
    foo in Child(Parent)
    foo in Parent
    
    foo in Child(Parent)
    (infinite recursion follows)
    

    为什么会这样?g是父代的别名,但它正在访问子代的foo(父代)?

    2 回复  |  直到 14 年前
        1
  •  3
  •   ZeissS    14 年前

    这不是一个 Double Dispatching ?


    更新:

    class Function {
        public void add(Function f) {
            f.addMe(this);
        }
    
        public void addMe(Function f) {
            // Default case
            throw NotImplementedException();
        }
        public void addMe(Logarithmic log) {
            // Code that handles the real
        }
    }
    
    class Logarithmic extends Function {
        // This object supports adding
        public void add(Function f) {
            f.addMe(this);
        }
    }
    
    
    Logarithmic log = new Logarithmic();
    log.add(new Function()); 
    log.add(new Logarithmic()); 
    
    Function f = log;
    f.add(new Function()); 
    f.add(new Logarithmic()); 
    
        2
  •  0
  •   Nate    14 年前

    我通过显式重写来实现 foo(Parent arg) 在里面 Child 像这样——

    class Parent {
        public void foo(Parent arg) {
            System.out.println("foo in Parent");
        }
    }
    
    class Child extends Parent {
        @Override
        public void foo(Parent arg) {
            System.out.println("foo in Child(Parent)");
            if (arg instanceof Child) {
                foo((Child)arg);
            } else {
                super.foo(arg);
            }
        }
        public void foo(Child arg) {
            System.out.println("foo in Child(Child)");
        }
    }
    

    这似乎符合

    我想“部分重写”父的foo(),也就是说,如果参数arg的类型是child,那么调用child的foo()而不是父的foo()。

    但实际上,您必须重写该方法,而不是“部分重写”该方法。