2013-04-04 12 views
10

Mam następujący kod, w tym samym pliku java.Java Flow of execution - nadpisywana metoda jest wykonywana najpierw niż konstruktor

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

Kiedy go uruchomić, wyjście daje mi

call to getSelectedFile

constructor call

call to getSelectedFile

Gdyby nie wyjście być

constructor call

call to getSelectedFile

Używam java 5.

+0

Gdzie jest wezwanie do getSelectedFile? –

+0

Moja zła, właściwie w moim oryginalnym kodzie, nazywam to zwykłym sposobem, po utworzeniu MyFileChooser. Ale jak widzisz, nawet jeśli nie robię jednoznacznego połączenia z 'getSelectedFile'. Zaktualizuję mój kod. – Bnrdo

+0

nigdy nie musisz wywoływać 'getSelectedFile', to wywołanie wewnątrz 'JFileChooser' kiedy wybierzesz plik –

Odpowiedz

8

MyFileChooser 's konstruktora jest równoznaczne z:

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

Pierwsze wywołanie getSelectedFile() dokonuje MyFileChooser' s baza klasy konstruktor, który jest wywoływany domyślnie w punkcie oznaczonym *** powyżej, przed System.out.println("constructor call").

Oto ślad stosu:

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

Aby zapobiec takim problemom, wszystkie metody wywoływane przez konstruktor powinny być ostateczne, aby nie mogły zostać nadpisane przez podklasę. – MatsT

1

Konstruktor:

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

wydaje się mieć nic wspólnego z klasy bazowej konstruktora. Istnieje jednak niejawne super wywołanie javax.swing.JFileChooser(), które wywołuje funkcję getSelectedFile();. Więc konstruktor jest rzeczywiście tak:

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

Ponieważ JFC jest przedmiotem MyFileChooser ta metoda:

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

jest sprawdzony. Wywoływane jest "call to getSelectedFile", a następnie "call to getSelectedFile".

1

Jeśli spojrzeć na ślad stosu, zobaczysz, że konstruktor JFileChooser wzywa setup(FileSystemView view) który wywołuje updateUI(), który nazywa setUI() w nadrzędnej JComponent, który wzywa installUI na platformie klasy UI specyficzne, klasa ta wywołuje installComponents , który ponownie wywołuje getSelectedFile.

Cytat z Effective Java 2nd Edition:

Istnieje kilka więcej ograniczeń, że klasa musi przestrzegać, aby umożliwić dziedziczenie. Konstruktorzy nie mogą bezpośrednio lub pośrednio wywoływać zastępczych metod. Jeśli naruszysz tę regułę, spowoduje to awarię programu. Konstruktor superklasy działa przed konstruktorem podklas, więc metoda nadrzędna w podklasie zostanie wywołana przed uruchomieniem konstruktora podklasy. Jeśli metoda przesłaniania zależy od jakiejkolwiek inicjalizacji wykonywanej przez konstruktor podklasy, metoda nie będzie działać zgodnie z oczekiwaniami.

Ale oczywiście Toolkit Swing nie zawsze się do tego zalecenia ;-)

Pełna ślad stosu:

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) 
Powiązane problemy