关于方法覆盖

时间:2011-06-17 14:20:38

标签: java override

对于以下java代码段,“run”方法发生四次。关于这四次“跑”的关系我很困惑。原始代码很长,我只保留与我的问题相关的部分。

   1. public final class Job extends AbstractJob {  
   2.   private Job( ) {  
   3.   }  
   4.   public static void main(String[] args) throws Exception {    
   5.            new Job( ).run(new Path("testdata"), output, 10 );  
   6.   }  
   7.   
   8.   @Override  
   9.   public int run(String[] args) throws IOException, ClassNotFoundException,      InterruptedException {  
  10.         run(input, output, alpha0);  
  11.         return 0;  
  12.   }    
  13.   public void run(Path input,  Path output,  double alpha0)  
  14.     throws IOException, ClassNotFoundException, InterruptedException {      
  15.     ClusterDriver.run(directoryInput, output, alpha0);      
  16.   }  
  17. }  

我是否可以按如下方式解释此段代码的调用序列。

首先,调用第5行的run方法。由于其特殊的参数设置,3个参数,编译器自动使用第13行定义的run方法。(如果我们在第5行只有一个参数,那么编译器将使用第9行中定义的run方法。

对于第9行定义的run方法,它将在第10行调用run方法,该方法基本上是第13行定义的run方法。

我的理解是否正确?

4 个答案:

答案 0 :(得分:2)

是的,这是正确的,除了这是方法重载,而不是覆盖。

此类中定义了两个run方法,在第9行和第13行,具有不同数量的参数。因此,方法run 重载。 (如果在子类中重新定义虚拟基类方法,则会发生重写 - 它显然发生在第9行定义的方法上,正如其注释所证明的那样,但这在此特定问题中不起作用。)

有两次调用run(第5行和第10行),这两次调用都解决了使用3个参数调用方法(在第13行定义)。

答案 1 :(得分:0)

只有最后的运行方法定义很重要。

另一个运行方法(需要String[])调用此方法,因此它的作用类似于某种“代理”,而run中的另一个main调用{1}}方法可以选择调用两者中的任何一种 - “代理”运行方法(需要String[] args)或最后运行方法,实际上是“跑”。

答案 2 :(得分:0)

你已经把大部分事情做对了,但我想纠正的一些陈述是:

if we only have one parameter in line 5, then compiler will use the run method defined in line 9 instead.

这不完全正确,第9行的方法接受String[]类型参数,你需要传递一个数组来调用这个方法。

For the run method defined in line 9, it will call run method at line 10, which essentially is the run method defined at line 13.

在第10行,您将收到语法错误,因为在该方法中未定义input, output, alpha0。您需要接受传递String[] args参数并将其转换为input, output, alpha0参数,以调用run的其他实现。

答案 3 :(得分:0)

您的基本分析是正确的。

(只是为了澄清其他人提出的观点:重载是指方法具有相同名称但签名不同,而覆盖是指方法具有相同名称时和参数类型作为超类中的方法)

为了将来参考,你应该知道,在重载方法的情况下,Java中的方法解析(name + arguments - >方法选择)实际上很难理解。使用的确切行为写在Java Language Spec (JLS), section 15.12中,涉及一些一般性的细微之处:

  • 重载方法解析在编译时完成,而不是在运行时完成。 (在相同签名的方法中选择覆盖是在运行时根据最具体的子类方法完成的。)如果编译器知道参数是{{1的实例(例如,它的类是FooFoo的子类)然后它将使用Foo作为参数的类,而不是它的“真正的”类。

  • 确定使用哪种方法的问题包括:

    • 方法是否为varargs(最后一个参数Foo,例如...
    • 方法的声明参数是基元还是包装基元,例如foo(Object a, String... b) vs float
    • 一个方法的声明参数是否比另一个方法“更具体”(子类比它们的超类更具体)

这很复杂但你有基本的了解。