2013-04-04 2 views
10

Ich habe den folgenden Code, in der gleichen Java-Datei.Java Ablauf der Ausführung - überschriebene Methode wird zuerst ausgeführt als der 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; 
    } 
} 

Wenn ich es laufen, gibt der Ausgang mich

call to getSelectedFile

constructor call

call to getSelectedFile

Sollte nicht der Ausgang sein

constructor call

call to getSelectedFile

ich Java 5.

bin mit 'ist Konstruktor entspricht:

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

Der erste Aufruf von getSelectedFile() von MyFileChooser gemacht wird'

+0

Wo wird Ihr Anruf an getSelectedFile? –

+0

Meine schlechte, eigentlich in meinem ursprünglichen Code, ich rufe es den üblichen Weg, nach der Instantiierung von MyFileChooser. Aber wie du sehen kannst, auch wenn ich keinen expliziten Aufruf von 'getSelectedFile' mache. Ich werde meinen Code aktualisieren. – Bnrdo

+0

Sie müssen niemals 'getSelectedFile' aufrufen, dies ruft innerhalb von 'JFileChooser' auf, wenn Sie die Datei –

Antwort

8

MyFileChooser Konstruktor Basisklasse, welches implizit an dem oben mit *** gekennzeichneten Punkt aufgerufen wird, vor dem System.out.println("constructor call"). Hier

ist der 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

auswählen Um solche Probleme zu vermeiden, sollten alle Methoden, die von einem Konstruktor aufgerufen werden, endgültig sein, damit sie nicht von einer Unterklasse überschrieben werden können. – MatsT

1

Der Konstruktor:

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

scheint nichts mit der Basisklasse Konstruktor zu tun. Es gibt jedoch einen impliziten Superaufruf an javax.swing.JFileChooser(), der den Aufruf an getSelectedFile(); sendet. Also Ihr Konstruktor ist tatsächlich so:

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

Da JFC Objekt von MyFileChooser ist, diese Methode:

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

ist aufgerufen. "call to getSelectedFile" wird ausgedruckt, gefolgt von "call to getSelectedFile".

1

Wenn man sich die Stack-Trace sehen, werden Sie sehen, dass der JFileChooser Konstruktor setup(FileSystemView view) ruft die updateUI() aufruft, die setUI() im JComponent Super aufruft, die installUI auf einem plattformspezifischen UI-Klasse aufruft, diese Klasse ruft dann installComponents , die wieder getSelectedFile aufruft.

Ein Zitat von Effective Java 2nd Edition:

noch ein paar Einschränkungen gibt es, dass eine Klasse gehorchen müssen Erbe zu ermöglichen. Konstruktoren dürfen keine überschreibbaren Methoden direkt oder indirekt aufrufen. Wenn Sie diese Regel verletzen, führt dies zu einem Programmfehler. Der Superklassenkonstruktor wird vor dem Unterklassenkonstruktor ausgeführt, sodass die überschreibende Methode in der Unterklasse aufgerufen wird, bevor der Unterklassenkonstruktor ausgeführt wurde. Wenn die überschreibende Methode von einer vom Unterklassenkonstruktor ausgeführten Initialisierung abhängt, verhält sich die Methode nicht wie erwartet.

Aber natürlich ist der Swing-Toolkit nicht immer diesem Rat folgen ;-)

Voll 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) 
Verwandte Themen