2012-11-16 10 views
9

Vor einiger Zeit schrieb ich ein kleines Bildbetrachter/Verarbeitungsprogramm mit Java, ein Mini-Photoshop, wenn Sie so wollen.Java innere Klasse Verwendung und Instanziierung

Ich wollte dort ein Drop-Down-Menü, wo ich wählen könnte, welches der Bilder, die ich geöffnet habe, wäre "auf dem Tisch", dh. gezeigt und Methoden angewendet auf. Ich wollte, dass der Name des Bildes der Name des JMenuItem ist, das im Menü angezeigt wird. Ich wollte auch eine neue Schaltfläche, wenn ich ein neues Bild anlege.

Ich fragte mich seit einiger Zeit und schließlich diese Lösung, eine neue Klasse, die die Erstellung der neuen Schaltfläche behandelt, wenn ein Bild hinzugefügt wird. Der Code lautet wie folgt:

import java.awt.event.*; 
import javax.swing.*; 
import java.util.*; 


public class ImageList{ 

    private ArrayList<JMenuItem> list; 
    private ImageHandler main; 
    private ImageLevel img; 

    public ImageList() {} 

    public void setHandler(ImageHandler hand) { 
     main = hand; 
     img = main.getImg1(); 
    } 

    public void add(Buffer addi) { 
     final String added = addi.getName(); 
     JMenuItem uusi = new JMenuItem(added); 

     main.getMenu5().add(uusi); 
     uusi.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       img.setBuffer(added); 
       main.getScr().updateUI(); 
      } 
     }); 
    } 
} 

Dies funktioniert, wie es sollte. Für diese Seite übersetzte ich die ursprünglichen finnischen Namen ins Englische, wundere mich, warum ich sie ursprünglich auf Finnisch geschrieben habe ... Ich sauge an der Namensgebung.

Methode hinzufügen soll während des laufenden Programms mehrfach aufgerufen werden.

Was ich nicht wirklich verstehen kann, ist die innere Klassenimplementierung der Schnittstelle ActionListener, nämlich seine Kompilierung und wie es funktioniert.

Wenn ich zwei Tasten auf meiner Schnittstelle habe und ich möchte, dass sie verschiedene Dinge tun, brauche ich zwei innere Klassen, eine für jede, jede hat seine eigene innere Implementierung der Schnittstelle ActionListener. Aber in meinem Code gibt es eine Klasse, die die Arbeit von vielen zu erledigen scheint, eine kompilierte .class-Datei dafür, aber das Endergebnis funktioniert, als ob es viele wären.

Kann mich jemand zu diesem Thema unterrichten? Ist dieser Code hier eine Klasse und neue Schaltflächen sind Instanzen davon? Sind sie neue Klassen? Sollte es für jede neue Schaltfläche eine neue .class-Datei geben? etc ...

+3

Re. naming: 'new' ist ein reserviertes Wort, daher sollten Sie für diese Variable JMenuItem etwas anderes verwenden. – assylias

+0

@peter Wird das beheben. – Valtteri

+0

Betrachten Sie auch "Action", wie in diesem ['FileMenu'] (http:// Stackoverflow.com/a/4039359/230513) – trashgod

Antwort

5

Oft eine innere Klasse in einem Code instanziiert wird, die nur einmal aufgerufen wird (zum Beispiel, wenn Sie JPanel erweitern und ActionListeners zu JButton s im Konstruktor hinzufügen). Hier instanziieren Sie eine innere Klasse in einer Methode, die Sie mehrmals aufrufen (wenn ich Ihre Beschreibung richtig verstehe). Jedes Mal, wenn Sie add() aufrufen, wird eine neue Instanz der inneren Klasse erstellt. Wie bei benannten Klassen gibt es nur eine Klasse, aber es kann viele Instanzen geben.

+0

+1 für die tatsächliche Beantwortung der OP-Frage gezeigt. – Perception

+0

@ Code-Guru: OK, also sind sie neue Instanzen. Nie wirklich gesehen oder zumindest nie bemerkt, innere Klassen mit mehr als einer Instanz. – Valtteri

+0

@Valtteri Genau. Siehe [Ted Hopps Antwort] (http://stackoverflow.com/questions/13420151/java-inner-class-usage-and-instantiation/13420335#13420335) für eine Erklärung über das Gleiche mit einer benannten inneren Klasse. Die beiden sind äquivalent, was das Erstellen von Instanzen betrifft. –

0

Sie erstellen neue anonyme Klassen für Ihre Menüelement-Aktionslistener.

Grundsätzlich Code

menuItem.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
}); 

Definiert eine neue Klasse Implementierung für die Action

+2

Dies ist nicht korrekt. Die anonymen Klassen werden zur Kompilierzeit nicht zur Laufzeit erstellt. – Renato

+1

Dieser Code erstellt neue * Objekte * aus einer einzigen * Klasse *. –

0
  • main.getScr().updateUI(); für die Aktualisierung bereits sichtbar Swing-Objekte nicht die richtige Methode ist, ist diese Methode empfindlich Look and Feel

  • Verwenden Sie JPanel (vergessen Sie nicht, PreferredSize außer Kraft zu setzen, gibt zurück Dimension (0, 0)) mit paintComponent,

  • , wenn Sie einen neuen Container fügen Sie dann ot entfernen möchten, das Bild halten, dann müssen Sie revalidate() und repaint()


  • Verwendung JList mit Bilder rufen statt JMenuItem

  • hinzufügen ListSelectionListener t o JList, dann können Sie betweens Bilder


  • wenn nicht hinzugefügt wird, jede andere JComponent (n) an die Container hält Image wechseln, dann JLabel zu verwenden, mit Icon/ImageIcon
+1

-1 Beantwortet die Frage des OP nicht. –

+0

grundlegende Sachen, nur um Schüsse in die Dunkelheit zu vermeiden, die hier beschrieben werden – mKorbel

+0

@mKorbel Ja, ich weiß, jemand würde mich mit diesen Ratschlägen beschießen: D Danke für sie trotzdem. Ich verstehe immer noch nicht wirklich GUI und so im Grunde überhaupt, also ist dieser Code sehr gespuckt und Stahldraht und es ist ein Wunder, dass es zusammenhält ... Wird Ihre Ratschläge auf jeden Fall durchlesen. – Valtteri

3

In diesem Code:

public void add(Buffer addi) { 
    . . . 
    uusi.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      img.setBuffer(added); 
      main.getScr().updateUI(); 
     } 
    }); 
} 

Das new ActionListener() {...} Konstrukt ist eine anonyme innere Klasse. Es verhält sich so, als wäre es separat als reguläre innere Klasse deklariert. Der Hauptunterschied besteht darin, dass der Name automatisch vom Compiler generiert wird. Es ist äquivalent zu:

private class Anonymous implements ActionListener { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
} 

public void add(Buffer addi) { 
    . . . 
    uusi.addActionListener(new Anonymous()); 
} 

Jedes Mal, wenn Sie Ihren addActionListener Code ausführen, eine neue Instanz dieser Klasse erstellt.

Anonyme innere Klassen haben einige andere Einschränkungen, die Folgen der Anonymität sind. Wenn sie beispielsweise Felder deklarieren, sind die Felder nur innerhalb der Klasse zugänglich (ohne Verwendung von Reflektion).

+0

+1 für die Erklärung der Gleichwertigkeit mit Eine benannte innere Klasse –

+0

Der Unterschied zwischen den beiden ist, dass die anonyme innere Klasse Zugriff auf die 'finalen' lokalen Variablen ihres enthaltenden Kontexts hat (dh' hinzugefügt'), aber die 'Anonymous'-Klasse, wie Sie es geschrieben haben, nicht (weil es außerhalb der Methode ist). Sie können die 'private class Anonymous' innerhalb der 'add'-Methode verschieben, um sie dem OP-Code korrekt zuzuordnen. –

+0

main.getScr(). UpdateUI(); Bitte was ist in dieser Codezeile gültig ??? – mKorbel

0

Sie erstellen eine anonyme Implementierung der Schnittstelle ActionListener. Jede anonyme Implementierung besitzt eine eigene Klassendatei (ImageList $ 1.class, ImageList $ 2.class usw.).

Sie könnten auch etwas tun, mit ähnlichen Ergebnissen:

class MyActionListener implements ActionListener { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
}; 

menuItem.addActionListener(new MyActionListener()); 
0

Eine innere Klasse innerhalb einer Klasse kompiliert ist in die ‚Eltern‘ .class-Datei. Sie können innerhalb einer Klasse mehrere innere Klassen haben. (resultierend in 1.Klassendateien nach dem Kompilieren) Jeder 'Aufruf' an eine innere Klasse (Runtime) erzeugt ein Objekt dieser inneren Klasse (dasselbe wie 'norma classes'). Aber es ändert Ihre .class-Dateien nicht.

Also, wenn 3 Tasten des gleichen Typs hinzufügen, dann jedes Mal ein neues Objekt der Innenklasse erstellt wird. Das gleiche Prinzip wie für den Button selbst.