2013-04-04 13 views
10

Ho il seguente codice, nello stesso file java.Java Flusso di esecuzione - il metodo sovrascritto viene eseguito prima del costruttore

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

quando l'eseguo, l'uscita mi dà

call to getSelectedFile

constructor call

call to getSelectedFile

Non dovrebbe essere l'uscita

constructor call

call to getSelectedFile

sto usando Java 5.

+0

casi in cui è chiamata a getSelectedFile? –

+0

Il mio male, in realtà nel mio codice originale, sto chiamando il solito modo, dopo l'istanziazione di MyFileChooser. Ma come puoi vedere, anche se non faccio una chiamata esplicita a 'getSelectedFile'. Aggiornerò il mio codice – Bnrdo

+0

non è necessario chiamare 'getSelectedFile', questo sta chiamando all'interno di 'JFileChooser' quando si sceglie il file –

risposta

8

MyFileChooser 's costruttore è equivalente a:

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

La prima chiamata a getSelectedFile() è fatta da MyFileChooser' s base di costruttore di classe, che viene invocato implicitamente nel punto contrassegnato da ***, prima dello System.out.println("constructor call").

Ecco la traccia dello stack:

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

Per evitare problemi come questo, tutti i metodi richiamati da un costruttore devono essere resi definitivi in ​​modo che non possano essere sovrascritti da una sottoclasse. – MatsT

1

Il costruttore:

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

sembra avere nulla a che fare con il costruttore della classe base. Tuttavia, esiste una chiamata super implicita a javax.swing.JFileChooser(), che effettua la chiamata a getSelectedFile();. Così il vostro costruttore è in realtà in questo modo:

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

Perché JFC è oggetto di MyFileChooser, questo metodo:

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

è ottenere chiamato. "call to getSelectedFile" viene stampato, seguito da "call to getSelectedFile".

1

Se si guarda la traccia dello stack, vedrai che il costruttore JFileChooser chiama setup(FileSystemView view) che chiama updateUI(), che chiama setUI() nella superclasse JComponent, che chiama installUI su una classe di interfaccia utente specifico per la piattaforma, questa classe quindi chiama installComponents , che chiama di nuovo getSelectedFile.

Una citazione da Effective Java 2nd Edition:

Ci sono alcune più restrizioni che una classe deve obbedire per consentire l'ereditarietà. I costruttori non devono invocare metodi sovrascrivibili, direttamente o indirettamente. Se si viola questa regola, si verificherà un errore del programma. Il costruttore della superclasse viene eseguito prima del costruttore della sottoclasse, quindi il metodo di override della sottoclasse verrà richiamato prima dell'esecuzione del costruttore della sottoclasse. Se il metodo di sostituzione dipende da qualsiasi inizializzazione eseguita dal costruttore della sottoclasse, il metodo non si comporterà come previsto.

Ma, naturalmente, il toolkit dell'oscillazione non segue sempre questo consiglio ;-)

completa analisi dello stack:

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) 
Problemi correlati