Java执行流程 - 重写方法首先执行,而不是构造函数

时间:2013-04-04 07:28:29

标签: java debugging

我在同一个java文件中有以下代码。

import javax.swing.SwingUtilities;
import java.io.File;

public class MainClass2{
   public static void main(String[] args){
       SwingUtilities.invokeLater(new Runnable(){
             public void run() {
                 javax.swing.JFileChooser jfc = new MyFileChooser();
                     File file = jfc.getSelectedFile();
             }

      });
   }
}

class MyFileChooser extends javax.swing.JFileChooser{
    public MyFileChooser(){
        System.out.println("constructor call");
    }
    @Override
    public java.io.File getSelectedFile(){
        System.out.println("call to getSelectedFile");
        return null;
    }
}

当我运行它时,输出给了我

call to getSelectedFile

constructor call

call to getSelectedFile

输出不应该是

constructor call

call to getSelectedFile

我正在使用java 5.

3 个答案:

答案 0 :(得分:8)

MyFileChooser的构造函数相当于:

public MyFileChooser() {
    super(); // ***
    System.out.println("constructor call");
}

getSelectedFile()的第一次调用是由MyFileChooser的基类构造函数构成的,该构造函数在***之前的System.out.println("constructor call")上隐式调用。 }。

这是堆栈跟踪:

MyFileChooser.getSelectedFile() line: 16    
AquaFileChooserUI.installComponents(JFileChooser) line: 1436    
AquaFileChooserUI.installUI(JComponent) line: 122   
MyFileChooser(JComponent).setUI(ComponentUI) line: 670  
MyFileChooser(JFileChooser).updateUI() line: 1798   
MyFileChooser(JFileChooser).setup(FileSystemView) line: 360 
MyFileChooser(JFileChooser).<init>(File, FileSystemView) line: 333  
MyFileChooser(JFileChooser).<init>() line: 286  
MyFileChooser.<init>() line: 11 

答案 1 :(得分:1)

构造函数:

public MyFileChooser(){
    System.out.println("constructor call");
}

似乎与基类的构造函数无关。但是有一个对javax.swing.JFileChooser()的隐式超级调用,它调用getSelectedFile();。所以你的构造函数实际上是这样的:

public MyFileChooser(){
    super();
    System.out.println("constructor call");
}

因为jfc是MyFileChooser的对象,所以这个方法:

@Override
public java.io.File getSelectedFile(){
    System.out.println("call to getSelectedFile");
    return null;
}

被调用。打印出“调用getSelectedFile”,然后“调用getSelectedFile”。

答案 2 :(得分:1)

如果你查看堆栈跟踪,你会看到JFileChooser构造函数调用setup(FileSystemView view)调用updateUI(),它调用JComponent超类中的setUI(),在特定于平台的UI类上调用installUI,然后该类调用installComponents,再次调用getSelectedFile

Effective Java 2nd Edition引用:

  

为了允许继承,类必须遵守一些限制。构造函数不得直接或间接调用可覆盖的方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行。

但是,当然,Swing工具包并不总是遵循这个建议; - )

完整堆栈跟踪:

at MyFileChooser.getSelectedFile(MainClass2.java:27)
    at com.apple.laf.AquaFileChooserUI.installComponents(AquaFileChooserUI.java:1436)
    at com.apple.laf.AquaFileChooserUI.installUI(AquaFileChooserUI.java:122)
    at javax.swing.JComponent.setUI(JComponent.java:670)
    at javax.swing.JFileChooser.updateUI(JFileChooser.java:1798)
    at javax.swing.JFileChooser.setup(JFileChooser.java:360)
    at javax.swing.JFileChooser.<init>(JFileChooser.java:333)