Java执行流重写方法比构造函数先执行

Java执行流重写方法比构造函数先执行,java,debugging,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.s

我在同一个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;
    }
}
当我运行它时,输出给我

调用getSelectedFile

构造函数调用

调用getSelectedFile

输出不应该是

构造函数调用

调用getSelectedFile


我正在使用java 5。

MyFileChooser
的构造函数相当于:

public MyFileChooser() {
    super(); // ***
    System.out.println("constructor call");
}
getSelectedFile()
的第一个调用是由
MyFileChooser
的基类构造函数进行的,该构造函数在
System.out.println(“构造函数调用”)
前面标记为
***
的点处隐式调用

以下是堆栈跟踪:

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 
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)
MyFileChooser.getSelectedFile()行:16
AquaFileChooserUI.installComponents(JFileChooser)行:1436
AquaFileChooserUI.installUI(JComponent)行:122
MyFileChooser(JComponent).setUI(ComponentUI)行:670
MyFileChooser(JFileChooser).updateUI()行:1798
MyFileChooser(JFileChooser).安装程序(FileSystemView)行:360
MyFileChooser(JFileChooser)。(文件,FileSystemView)行:333
MyFileChooser(JFileChooser)。()行:286
MyFileChooser。()行:11
构造函数:

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”。

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

引自《有效Java第二版》:

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

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

完整堆栈跟踪:

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 
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)
MyFileChooser.getSelectedFile(MainClass2.java:27)上的

位于com.apple.laf.AquaFileChooserUI.installComponents(AquaFileChooserUI.java:1436)
位于com.apple.laf.AquaFileChooserUI.installUI(AquaFileChooserUI.java:122)
位于javax.swing.JComponent.setUI(JComponent.java:670)
位于javax.swing.JFileChooser.updateUI(JFileChooser.java:1798)
位于javax.swing.JFileChooser.setup(JFileChooser.java:360)
位于javax.swing.JFileChooser。(JFileChooser.java:333)

对getSelectedFile的调用在哪里?My bad,实际上是在我的原始代码中,我在实例化MyFileChooser之后以通常的方式调用它。但正如您所看到的,即使我没有显式调用
getSelectedFile
。我将更新我的代码。您永远不需要调用
getSelectedFile
,这是在选择文件时在“JFileChooser”内部调用注意,在构造函数的开头有一个对
super()
的隐式调用,可能会调用其他方法。您还可以将
Thread.dumpStack()
添加到
getSelectFile()
以显示它是如何到达那里的。@Alya'a Gamal您说我不需要调用
getSelectedFile
是什么意思?那么,如何从对话框中选择文件呢?为了避免类似的问题,构造函数调用的所有方法都应该是最终的,这样子类就不能覆盖它们。