# Memory-Spiel



## Albi_2020 (27. Mai 2021)

Hallo,
ich habe in JavaFX versucht ein Memory-Spiel zu erstellen. Leider werden diverse Exceptions geworfen bei der Ausführung. Ich kann aber den Fehler nicht finden. Wäre super, wenn mir einer helfen könnte:

[CODE lang="java" title="MemoryKarte.java"]import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;

  //die Klasse für eine Karte des Memory-Spiels
  //Sie erbt von Button
  public class MemoryKarte extends Button {

  //die Instanzvariablen
  //eine eindeutige ID zur Identifizierung des Bildes
  private int bildID;

  //für die Vorder- und Rückseite
  private ImageView bildVorne, bildHinten;

  //wo liegt die Karte im Spielfeld
  private int bildPos;

  //ist die Karte umgedreht?
  private boolean umgedreht;

  //ist die Karte noch im Spiel?
  private boolean nochImSpiel;

  //die innere Klasse für den Eventhandler
  class KartenListener implements EventHandler<ActionEvent>{
      @Override
      public void handle(ActionEvent arg0) {
      //ist die Karte überhaupt noch im Spiel?
      if (nochImSpiel == false)
          return;
      //wenn die Rückseite zu sehen ist, die Vorderseite anzeigen
      if (umgedreht == false) {
          setGraphic(bildVorne);
          umgedreht = true;
      }
      }
  }

  //der Konstruktor
  //er setzt die Bilder
  public MemoryKarte(String vorne, int bildID) {

      //die Vorderseite, der Dateiname des Bildes wird an
      //den Konstruktor übergeben
      bildVorne = new ImageView(vorne);

      //die Rückseite, sie wird fest gesetzt
      bildHinten = new ImageView("Grafik/back.jpg");
      setGraphic(bildHinten);

      //die Bild-ID
      this.bildID = bildID;

      //die Karte ist erst einmal umgedreht und noch im Feld
      umgedreht = false;
      nochImSpiel = true;

      //die Action setzen
      setOnAction(new KartenListener());
  }

  //die Methode zeigt die Rückseite der Karte an
  public void rueckseiteZeigen(boolean rausnehmen) {

      //soll die Karte komplett aus dem Spiel genommen werden?
      if (rausnehmen == true) {
          //das Bild aufgedeckt zeigen und die Karte aus dem Spiel nehmen
          setGraphic(new ImageView("Grafik/aufgedeckt.jpg"));
          nochImSpiel = false;
      }
      else {
          //sonst nur die Rückseite zeigen
          setGraphic(bildHinten);
          umgedreht = false;
      }
  }

   //die Methode liefert die Bild-ID einer Karte
   public int getBildID() {
     return bildID;
   }

   //die Methode liefert die Position einer Karte
   public int getBildPos() {
     return bildPos;
   }

   //die Methode setzt die Position einer Karte
   public void setBildPos(int bildPos) {
     this.bildPos = bildPos;
   }
}[/CODE]

[CODE lang="java" title="MemoryFeld.java"]import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;

public class MemoryFeld {

    //das Array für die Karten
    private MemoryKarte[] karten;

    //das Array für die Namen der Grafiken
    private String[] bilder = {"Grafik/apfel.jpg", "Grafik/birne.jpg", "Grafik/blume.jpg", "Grafik/blume2.jpg", "Grafik/ente.jpg", "Grafik/fisch.jpg", "Grafik/fuchs.jpg", "Grafik/igel.jpg", "Grafik/kaenguruh.jpg", "Grafik/katze.jpg", "Grafik/kuh.jpg", "Grafik/maus1.jpg", "Grafik/maus2.jpg", "Grafik/maus3.jpg", "Grafik/melone.jpg", "Grafik/pilz.jpg", "Grafik/ronny.jpg", "Grafik/schmetterling.jpg","Grafik/sonne.jpg", "Grafik/wolke.jpg", "Grafik/maus4.jpg"};

    //für die Punkte
    private int menschPunkte, computerPunkte;

    //zwei Labels für die Punkte
    private Label menschPunkteLabel, computerPunkteLabel;

    //wie viele Karten sind aktuell umgedreht?
    private int umgedrehteKarten;

    //für das aktuell umdrehte Paar
    private MemoryKarte[] paar;

    //für den aktuellen Spieler
    private int spieler;

    //das Gedächtnis für den Computer
    //er speichert hier, wo das Gegenstück liegt
    private int[][] gemerkteKarten;

    //der Konstruktor
    public MemoryFeld() {

        //das Array für die Karten erstellen, insgesamt 42 Stück
        karten = new MemoryKarte[42];

        //für das Paar
        paar = new MemoryKarte[2];

        //für das Gedächtnis
        //es speichert für jede Karte paarweise die Position im Spielfeld
        gemerkteKarten = new int[2][21];

        //keiner hat zu Beginn einen Punkt
        menschPunkte = 0;
        computerPunkte = 0;

        //es ist keine Karte umgedreht
        umgedrehteKarten = 0;

        //der Mensch fängt an
        spieler = 0;

        //es gibt keine gemerkten Karten
        for (int aussen = 0; aussen < 2; aussen++)
            for (int innen = 0; innen < 21; innen++)
                gemerkteKarten[aussen][innen] = -1;
    }

    //die Methode erstellt die Oberfläche und zeichnet die Karten über eine eigene Methode
    //übergeben wird ein FlowPane
    public FlowPane initGUI(FlowPane feld) {

        //für die Ausgaben
        kartenZeichnen(feld);

        menschPunkteLabel = new Label();
        computerPunkteLabel = new Label();

        menschPunkteLabel.setText(Integer.toString(menschPunkte));
        computerPunkteLabel.setText(Integer.toString(computerPunkte));

        //in zwei Spalten anzeigen
        GridPane tempGrid = new GridPane();

        //und einfügen, dabei werden die Koordinaten angegeben
        tempGrid.add(new Label("Mensch: "), 0 , 0 );
        tempGrid.add(menschPunkteLabel, 1, 0);
        tempGrid.add(new Label("Computer: "), 0, 1);
        tempGrid.add(computerPunkteLabel, 1 ,1);
        feld.getChildren().add(tempGrid);
         return feld;
    }

    //das eigentliche Spielfeld erstellen
    private void kartenZeichnen(FlowPane feld) {
         int count = 0;
         for (int i = 0; i <= 41; i++) {

    //eine neue Karte erzeugen
    karten_ = new MemoryKarte(bilder[count], count);

    //bei jeder zweiten Karte kommt auch ein neues Bild
    if ((i + 1) % 2 == 0)
        count++;
    }

    //die Karten ins Spielfeld gesetzt
    for (int i = 0; i <= 41; i++) {
        feld.getChildren().add(karten);
        //die Position der Karte setzen
           karten.setBildPos(i);
    }
    }
}[/CODE]

[CODE lang="java" title="MemoryFX.java"]import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class MemoryFX extends Application{
    @Override
    public void start(Stage meineStage) throws Exception {

        //den obersten Knoten erzeugen
        //hier verwenden wir ein FlowPane
        //erzeugt wird die Oberfläche über eine eigene
        //Methode in der Klasse MemoryFeld
        FlowPane rootNode = new MemoryFeld().initGUI(new FlowPane());

        //die Szene erzeugen
        //an den Konstruktor werden der oberste Knoten und
        //die Größe übergeben
        Scene meineScene = new Scene(rootNode, 480, 550);

        //den Titel über stage setzen
        meineStage.setTitle("Memory");

        //die Szene setzen
        meineStage.setScene(meineScene);

        //Größenänderungen verhindern
        meineStage.setResizable(false);

        //und anzeigen
        meineStage.show();
}

      public static void main(String[] args) {
          //der Start
          launch(args);
      }
}[/CODE]_


----------



## Albi_2020 (27. Mai 2021)

ich habe die Exceptions vergessen:


[CODE lang="java" title="Exceptions"]Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
    at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1125)
    at javafx.graphics/javafx.scene.image.Image.<init>(Image.java:618)
    at javafx.graphics/javafx.scene.image.ImageView.<init>(ImageView.java:194)
    at MemoryFX/application.MemoryKarte.<init>(MemoryKarte.java:49)
    at MemoryFX/application.MemoryFeld.kartenZeichnen(MemoryFeld.java:94)
    at MemoryFX/application.MemoryFeld.initGUI(MemoryFeld.java:68)
    at MemoryFX/application.MemoryFX.start(MemoryFX.java:16)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:474)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:447)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:446)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
    at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1117)
    ... 12 more
Exception running application application.MemoryFX[/CODE]


----------



## kneitzel (27. Mai 2021)

Der Fehler besagt, dass eine Ressource nicht geladen werden kann. Die Zeile Code, die das auslöst, findet sich in 


Albi_2020 hat gesagt.:


> at MemoryFX/application.MemoryKarte.<init>(MemoryKarte.java:49)



Das ist bei der Code-Copy hier ein Kommentar, aber vermutlich hat sich da eine zusätzliche Zeile eingefügt oder so und es ist die Zeile:

```
bildHinten = new ImageView("Grafik/back.jpg");
```

Hier ist die Frage erst einmal, wo Du die Bilder abgelegt hast und wie Du das Projekt baust. Bei Maven / Gradle wäre das z.B. in src/main/resources richtig.

Die URL zum Laden einer Resource bekommt man dann per getClass().getResource("/Grafik/....jpg") bzw. MemoryKarte,class.getResource("/Grafik/....jpg"); (Ggf. den Klassennamen austauschen, so es in einer anderen Klasse zu finden ist!)


			Class (Java Platform SE 8 )


----------



## Albi_2020 (27. Mai 2021)

kneitzel hat gesagt.:


> Der Fehler besagt, dass eine Ressource nicht geladen werden kann. Die Zeile Code, die das auslöst, findet sich in
> 
> 
> Das ist bei der Code-Copy hier ein Kommentar, aber vermutlich hat sich da eine zusätzliche Zeile eingefügt oder so und es ist die Zeile:
> ...


Hallo Kneitzel,

danke erstmal für die Antwort. Ich weiß es ist verdammt wichtig dass mit den Exceptions zu verstehen, aber ich habe da echt meine Probleme da glaube ich noch nicht zu 100% verstanden.
Woher wusstest Du bei den vielen Fehlermeldungen, dass es genau diese ist?

Bei mir sind es folgende Codestreifen (zumindest die vier mit meinem Projekt):

[CODE lang="java" title="Exception"]MemoryFX/application.MemoryKarte.<init>(MemoryKarte.java:49)[/CODE]


```
bildVorne = new ImageView(vorne);
```

[CODE lang="java" title="Exception"]MemoryFX/application.MemoryFeld.kartenZeichnen(MemoryFeld.java:94)[/CODE]


```
karten[i] = new MemoryKarte(bilder[count], count);
```

[CODE lang="java" title="Exception"]MemoryFX/application.MemoryFeld.initGUI(MemoryFeld.java:68)[/CODE]


```
kartenZeichnen(feld);
```

[CODE lang="java" title="Exception"]MemoryFX/application.MemoryFX.start(MemoryFX.java:16)[/CODE]


```
FlowPane rootNode = new MemoryFeld().initGUI(new FlowPane())
```

Die Bilder liegen in einem Unterordner des Projektes selber. Das hatte ich auch schon bei einer Textverarbeitung so gelegt, da hat Eclipse das ohne Probleme gemacht. Wenn ich das Programm mit auskommentierter Methode *private* *void* kartenZeichnen(FlowPane feld) ausführe, dann läuft das Programm, zeigt mir aber nur die beiden Punktestände von Mensch und Computer an, aber kein Memory.


----------



## kneitzel (27. Mai 2021)

Albi_2020 hat gesagt.:


> Woher wusstest Du bei den vielen Fehlermeldungen, dass es genau diese ist?


So eine Exception ist wie eine Zwiebel. Es kommen ständig Schalen dazu. Uns interessiert aber immer nur die Schale, für die wir verantwortlich sind.

Du siehst also bei Dir erst einmal eine java.lang.reflect.InvocationTargetException.
Aber die war nicht ursächlich, den du findest ja danach noch:
Caused by: java.lang.RuntimeException: Exception in Application start method
Aber die war auch nicht die Ursache:
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
Und da dann noch:
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found

Für das Verständnis evtl. noch einfach die Exception Klasse ansehen: Da findet sich dann (geerbt von Throwable) noch die cause. (In anderen Sprechen teilweise als "inner exception" oder so benannt.

Das Pattern dabei ist immer dabei etwas wie:

```
try {
    // ...
} catch (SomeException ex) {
    // ...
    // Feststellung: Ich kann da nichts machen, also neue spezifische Exception werfen:
    throw new MySpecificException(whatever-is-usefull, ex); // <= ex wird mitgegeben!
}
```

Somit immer von unten nach oben gehen...
-> Erst kommt da etwas in Image -> Nicht Dein Code, interessiert nur am Rande (daher auch gekürzt worden ...)
-> Dann kommt die Exception in Deinem Code -> Stacktrace ist wichtig:

Hier bitte von unten nach oben den Stacktrace anschauen:

```
// 5. im ImageView Konstruktor hast Du dann ein Problem mit der URL / resource nicht da ...
    at javafx.graphics/javafx.scene.image.ImageView.<init>(ImageView.java:194)
        
    // 4. Da ist es dann in Zeile 49 zu einem Problem gekommen mit dem ImageView Konstruktor ...
    at MemoryFX/application.MemoryKarte.<init>(MemoryKarte.java:49)
        
    // 3. in MemoryFeld.kartenZeichnen (Zeile 94) wird der Konstruktor von MemoryKarte aufgerufen.
    at MemoryFX/application.MemoryFeld.kartenZeichnen(MemoryFeld.java:94)
        
    // 2. in initGUI (Zeile 68) wird karteZeichnen aufgerufen.
    at MemoryFX/application.MemoryFeld.initGUI(MemoryFeld.java:68)
        
    // 1. In MemoryFX.start wurde in Zeile 16 initGUI() gestartet...
    at MemoryFX/application.MemoryFX.start(MemoryFX.java:16)
```

Das Problem ist, dass Du die Bilde nicht als Dateien laden solltest, denn dann gibt es Probleme, weil die Ordnerstruktur immer passen muss ... Das sind aber Ressourcen und dafür hat Java ein spezielles Vorgehen und das habe ich grob skizziert. Das solltest Du verwenden, denn dann funktioniert es auch mit Eclipse ....

Wenn Du nur ein einfaches Eclipse Projekt hast, dann gehört der Ordner mit den Grafiken direkt in den src Ordner.


----------



## Albi_2020 (28. Mai 2021)

Hallo Kneitzel,
erstmal vielen Dank für die ausführliche Erläuterung. Ich habe alles versucht mit den Bildern. Es erscheint immer die Exception...

Ich habe jetzt die Bilder in die src gespeichert....aber wie muss das Bild angesprochen werden?


```
bildHinten = new ImageView("grafik/back.jpg");
```


```
bildHinten = new ImageView("/grafik/back.jpg");
```


```
bildHinten = new ImageView("/back.jpg");
```


```
bildHinten = new ImageView("back.jpg");
```

Ich verzweifele langsam


----------



## Barista (28. Mai 2021)

Albi_2020 hat gesagt.:


> Ich habe jetzt die Bilder in die src gespeichert....aber wie muss das Bild angesprochen werden?


Als Notlösung kannst Du erst mal den Dateinamen mit vollem Pfad angeben.

Wenn Du es später perfekt machen willst, Suche mal nach "Java resource as stream".


----------



## mihe7 (28. Mai 2021)

Albi_2020 hat gesagt.:


> Ich habe jetzt die Bilder in die src gespeichert....aber wie muss das Bild angesprochen werden?




```
bildHinten = new ImageView(getClass().getResource("/grafik/back.jpg"));
```
Wo sich das Verzeichnis grafik in Deinem Projektverzeichnis befinden muss, hängt vom verwendeten Buildsystem ab. Wenn Dein Projektverzeichnis src/main/java enthält, solltest Du es mal unter src/main/resources legen. Anonsten könnte es funktionieren, wenn es unter src liegt.


----------



## kneitzel (28. Mai 2021)

kneitzel hat gesagt.:


> Die URL zum Laden einer Resource bekommt man dann per getClass().getResource("/Grafik/....jpg") bzw. MemoryKarte,class.getResource("/Grafik/....jpg"); (Ggf. den Klassennamen austauschen, so es in einer anderen Klasse zu finden ist!)
> Class (Java Platform SE 8 )


----------



## Albi_2020 (28. Mai 2021)

In meinem Projekt liegen die Bilder hier:


----------



## Albi_2020 (28. Mai 2021)

und wie werden die Bilder im Array angesprochen?


```
//das Array für die Namen der Grafiken
    private String[] bilder = {"grafik/apfel.jpg", "grafik/birne.jpg", "grafik/blume.jpg", "grafik/blume2.jpg", "grafik/ente.jpg", "grafik/fisch.jpg", "grafik/fuchs.jpg", "grafik/igel.jpg", "grafik/kaenguruh.jpg", "grafik/katze.jpg", "grafik/kuh.jpg", "grafik/maus1.jpg", "grafik/maus2.jpg", "grafik/maus3.jpg", "grafik/melone.jpg", "grafik/pilz.jpg", "grafik/ronny.jpg", "grafik/schmetterling.jpg","grafik/sonne.jpg", "grafik/wolke.jpg", "grafik/maus4.jpg"};
```


----------



## kneitzel (28. Mai 2021)

getResource nimmt einen String. Woher der kommt ist egal. Groß-/Kleinschreibung beachten. Führenden / beachten.

Somit ist es Java egal, wie du es genau hast:

```
getClass().getResource("/grafik/picture.jpg");
getClass().getResource(bilder[i]); // bilder[i] ist dann der String vom ersten Beispiel.
getClass().getResource("/" + bilder[i]); // hier wäre bilder[i] ohne führenden /
```
 
Dabei ist da jetzt nur der Code gezeigt, der die URL zurück gibt, die Du dann statt dem bisherigen String / Array Element angibst.


----------



## Albi_2020 (28. Mai 2021)

hier ist mein Projekt....es hat jemand getestet und bei ihm funktioniert es ohne Probleme. Bei mir nur mit Exception....müssen irgendwo in Eclipse noch einstellungen gemacht werden?
classpath
build path o.ä.


----------



## kneitzel (28. Mai 2021)

Du hast ja auch in keiner Weise umgesetzt, was wir Dir gesagt haben.... Also was erwartest Du?


----------



## Albi_2020 (28. Mai 2021)

kneitzel hat gesagt.:


> Du hast ja auch in keiner Weise umgesetzt, was wir Dir gesagt haben.... Also was erwartest Du?


doch ich hatte es auch mit euren/deinen Anmerkungen probiert....aber jedesmal der gleiche Fehler...
mein Problem ist irgendwie die einzelnen Bilder für das Array einzutragen {"....jpg", "...jpg}...vermutlich rührt daher der Fehler

das zip ist noch vom 1. versuch....aber es scheint trotzdem zu laufen...nur nicht auf meinem Mac


----------



## kneitzel (28. Mai 2021)

Also nur um das Gesagte noch einmal an einem konkreten Beispiel aufzuzeigen, nehme ich einfach eine Zeile aus MemoryKarte.java:


```
bildVorne = new ImageView(vorne);
      bildHinten = new ImageView("grafik/back.jpg");
```

Sollte in das geändert werden:


```
bildVorne = new ImageView(getClass().getResource("/" + vorne));
      bildHinten = new ImageView(getClass().getResource("/grafik/back.jpg"));
```

Es werden alle Resourcen über diesen Mechanismus geladen. Das muss also an allen Stellen so sein. Und statt das / mit + davor zu setzen kannst Du es auch direkt im Array verändern (was ich anraten würde).


----------



## Albi_2020 (28. Mai 2021)

ok bildVorne hatte ich nicht so geändert…das leuchtet mir auch irgendwie ein…aber was ich so null verstehe ist die Deklaration des Arrays


```
private String[] bilder = {"Grafik/apfel.jpg",
```

die ganzen Bilder sollen doch in das Array bilder…muss ich da dann auch mit getClass() arbeiten?


----------



## Mart (28. Mai 2021)

getClass ist dein Datei Pfad zu deiner Klasse der unabhängig vom datei system ist ...es heist nur dass in dem ordner in dem sich die klasse befindet sicch auch die Bilder befinden


----------



## Barista (28. Mai 2021)

Mart hat gesagt.:


> getClass ist dein Datei Pfad zu deiner Klasse der unabhängig vom datei system ist ...es heist nur dass in dem ordner in dem sich die klasse befindet sicch auch die Bilder befinden


Nein.

Es geht nur darum, den aktuellen ClasLoader zu bekommen.


----------



## kneitzel (28. Mai 2021)

Ich habe es ja bereits bei der ersten Erwähnung verlinkt und auch das Geschriebene noch einmal geteilt gehabt ...

getClass() gibt einem nur eine Instanz der Klasse. Diese hat eine Möglichkeit, Ressourcen über den Classloader zu laden. Die Doku zu getResource habe ich verlinkt, da dort erklärt ist, wie die Ressourcen gefunden werden. getResource sucht relativ vom Package der Klasse. getResource vom Classloader würde nicht relativ zur Klasse suchen.
Der Unterschied ist aber egal, da wir ja ein / voran gestellt haben (oder ich zumindest mehrfach darauf hingewiesen habe!)


----------



## mihe7 (28. Mai 2021)

Albi_2020 hat gesagt.:


> ok bildVorne hatte ich nicht so geändert…das leuchtet mir auch irgendwie ein…aber was ich so null verstehe ist die Deklaration des Arrays
> 
> 
> ```
> ...


Vielleicht muss man an der Stelle etwas ausholen. Ich stelle das zum besseren Verständnis stark gekürzt dar, tatsächlich verhält es sich etwas komplizierter.

Java verwendet sog. ClassLoader, um nach Klassen in einem Pfad zu suchen, der als Classpath bezeichnet wird. Über diesen Mechanismus ist es möglich, nicht nur Klassen, sondern auch zum Programm gehörige Ressourcen zu laden. Eine Möglichkeit dafür ist z. B. die Methode getResource(pfad) der Klasse Class.

Was ist nun aber als Argument für den Parameter pfad anzugeben? Es ist nicht der Pfad auf Deiner Festplatte, sondern der Pfad innerhalb Deiner Anwendung. 

Nun darfst Du nicht davon ausgehen, dass die Verzeichnisstruktur Deines Projekts genau der Struktur Deiner Anwendung entspricht. In der Regel werden die .java-Dateien übersetzt und die dabei entstehenden .class-Dateien an anderer Stelle (z. B. build/classes oder target/classes) abgelegt. Ebenso werden Ressourcen dorthin kopiert. Am Ende hast Du also einen Verzeichnisbaum, in dem .class-Dateien und Ressourcen gleichermaßen liegen.

Beim Ausführen wird die Wurzel dieses Verzeichnisbaums (z. B. build/classes) als Classpath gesetzt. Relativ zu diesem Verzeichnis werden Klassen und Ressourcen vom Classloader gesucht. Gibst Du also als Ressourcennamen /grafik/apfel.jpg an, findet der Classloader die Ressource nicht etwa unter C:/grafik/apfel.jpg und auch nicht unter src/grafik/apfel.jpg sondern unter build/classes/grafik/apfel.jpg. 

Kurz: Du lässt bei der Angabe die Wurzel des Verzeichnisbaums weg, in dem die Quelltexte bzw. Ressourcen liegen. 

Vielleicht werden nun die Ausführungen der anderen etwas klarer.


----------



## Albi_2020 (28. Mai 2021)

super…vielen Dank an Alle


----------

