10

我在同一个 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。

4

3 回答 3

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 
于 2013-04-04T07:48:51.047 回答
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”。

于 2013-04-04T07:58:07.610 回答
1

如果您查看堆栈跟踪,您会看到JFileChooser构造函数调用setup(FileSystemView view)which calls updateUI(),它调用setUI()JComponent 超类,它调用installUI特定于平台的 UI 类,然后这个类调用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)
于 2013-04-04T08:01:59.830 回答