2013-04-04 24 views
10

Tôi có mã sau, trong cùng một tệp java.Java Luồng thực thi - phương pháp ghi đè được thực thi đầu tiên so với hàm tạo

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; 
    } 
} 

Khi tôi chạy nó, kết quả mang lại cho tôi

call to getSelectedFile

constructor call

call to getSelectedFile

nên không phải là đầu ra được

constructor call

call to getSelectedFile

Tôi đang sử dụng java 5.

+0

đâu cuộc gọi của bạn để getSelectedFile? –

+0

Cái xấu của tôi, thực sự trong mã ban đầu của tôi, im gọi nó theo cách thông thường, sau khi khởi tạo MyFileChooser. Nhưng như bạn có thể thấy, ngay cả khi tôi không thực hiện lệnh gọi 'getSelectedFile'. Tôi sẽ cập nhật mã của mình. – Bnrdo

+0

bạn không bao giờ cần phải gọi 'getSelectedFile', đây là gọi bên trong 'JFileChooser' khi bạn chọn tệp –

Trả lời

8

MyFileChooser 's constructor tương đương với:

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

Cuộc gọi đầu tiên getSelectedFile() được thực hiện bởi MyFileChooser' s lớp cơ sở xây dựng, được gọi ngầm tại điểm được đánh dấu *** ở trên, trước System.out.println("constructor call").

Đây là stack trace:

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 
+0

Để ngăn chặn các vấn đề như thế này, tất cả các phương thức được gọi bởi một hàm tạo nên được thực hiện cuối cùng để chúng không thể bị ghi đè bởi một lớp con. – MatsT

1

Các constructor:

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

dường như không có gì để làm với các lớp cơ sở constructor. Tuy nhiên, có một cuộc gọi siêu tiềm ẩn đến javax.swing.JFileChooser(), thực hiện cuộc gọi đến getSelectedFile();. Vì vậy, nhà xây dựng của bạn thực sự là như thế này:

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

Vì JFC là đối tượng của MyFileChooser, phương pháp này:

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

là được gọi. "call to getSelectedFile" được in ra, tiếp theo là "call to getSelectedFile".

1

Nếu bạn nhìn vào stack trace, bạn sẽ thấy rằng các nhà xây dựng JFileChooser gọi setup(FileSystemView view) trong đó kêu gọi updateUI(), trong đó kêu gọi setUI() trong lớp cha JComponent, trong đó kêu gọi installUI trên một lớp giao diện người dùng nền tảng cụ thể, lớp này sau đó gọi installComponents gọi lại getSelectedFile.

Một trích dẫn từ Effective Java 2nd Edition:

Có một vài chi tiết hạn chế mà một lớp phải tuân theo để cho phép thừa kế. Các nhà xây dựng không được gọi các phương thức có thể ghi đè, trực tiếp hoặc gián tiếp. Nếu bạn vi phạm quy tắc này, lỗi chương trình sẽ xảy ra. Trình xây dựng siêu lớp chạy trước hàm tạo lớp con, do đó phương thức ghi đè trong lớp con sẽ được gọi trước khi hàm tạo lớp con chạy. Nếu phương thức ghi đè phụ thuộc vào bất kỳ khởi tạo nào được thực hiện bởi hàm tạo lớp con, thì phương thức sẽ không hoạt động như mong đợi.

Nhưng tất nhiên, bộ công cụ Swing không phải lúc nào làm theo lời khuyên này ;-)

Full stack trace:

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) 
Các vấn đề liên quan