Seriallisierung: problem bei methode read()

Die Aufgabestellung ist folgende
**
Interface FahrzeugDAO:

Dieses Interface definiert die Data Access Object (DAO) Methoden für persistente Fahrzeug Objekte. Das DAO Interface soll Methoden zum Einlesen und zum Auslesen von Fahrzeug Objekten aus einer Datei definieren. Die Methode readFahrzeuge() soll einen Vector mit allen verfügbaren Fahrzeug Objekten zurückgeben. Der Methode storeFahrzeuge(Vector) soll ein Vector mit Fahrzeugen übergeben werden.

Klasse SerializedFahrzeugDAO :

Diese Klasse ist eine Implementierung des Interface FahrzeugDAO, und realisiert die Methoden readFahrzeuge() sowie storeFahrzeuge(Vector). Diese Klasse soll einen Konstruktor haben dem der Filename übergeben wird. Die Klasse soll alle Fahrzeuge (als Vector) in eine Datei serialisieren und diese wieder auslesen.
**



public interface FahrzeugDAO {

	public ArrayList<Fahrzeug> readFahrzeuge();
	
	public void storeFahrzeuge(ArrayList<Fahrzeug> fahrzeuge);
	

}
public class SerializedFahrzeugDAO implements FahrzeugDAO {

	private final String dateiname;

	public SerializedFahrzeugDAO(String dateiname) {
		this.dateiname = dateiname;

	}

	public void storeFahrzeuge(ArrayList<Fahrzeug> fahrzeuge) {

		try {
			ObjectOutputStream out = new ObjectOutputStream(
					new FileOutputStream(dateiname));

			out.writeObject(fahrzeuge);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public ArrayList<Fahrzeug> readFahrzeuge() {
		ArrayList<Fahrzeug> fahrzeuge = new ArrayList<Fahrzeug>();
		Fahrzeug auto;
		try {

			ObjectInputStream in = new ObjectInputStream(new FileInputStream(
					dateiname));
			auto = (Fahrzeug) in.readObject();
			fahrzeuge.add(auto);
			in.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return fahrzeuge;
	}

}

ist das komplette Blödsinn oder passt so? besonderes interessiert mich die Methode readFahrzeuge()

Danke Anni

Sieht schon recht ordentich aus. Mir gefällt auch, dass Du den antiquierten Aufgabentext mit Vector selbständig in Richtung List gebracht hast.

Aber so ganz passt es nicht. Du sollst ja eine Liste von Autos speichern/laden. So wie Du beim Speichern die komplette Liste serialisierst, kriegst Du natürlich beim Laden auch eine Liste wieder raus und nicht ein einzelnes Auto. Das ist ein Fehler, der zur Laufzeit mit ClassCastException quittiert werden wird.

Und als kleinen Verbesserungsvorschlag: Definier die Methoden mit List nicht mit ArrayList.

Sieht beim ersten Überfliegen (bitte Hitze+Fr.Nachmittag berücksichtigen ;)) nicht komplett falsch aus. In der Aufgabenstellung ist explizit „Vector“ gefordert, und nicht ArrayList, aber das ist beides IMHO nicht so optimal: In den Methodensignaturen sollte IMHO jeweils NUR ‚List‘ verwendet werden (das kann dann ein Vector sein, oder eine ArrayList, oder eine LinkedList, oder oder oder…).

Ansonsten stimmt die read-Methode aber nicht mit der write-Methode überein: Einmal wird eine Liste von Autos geschrieben, und einmal nur versucht (!) ein einzelnes Auto zu lesen (das dann in eine Liste gepackt werden soll…)

EDIT: Boah… bin ich lahm… aber darauf bezog sich ja der Einlass in den (Klammern) :wink:

@Marco13 : Brüder im Geiste :smiley:

@Marco13 : das ist nicht wirklich Aufgabe, die ich jemanden abgeben soll. Ich habe nur einpaar Beispiele mir zum lernen besorgt. ich lerne java (selbständig) + (eure Unterstützung)

jetzt soll das stimmen oder?

public class SerializedFahrzeugDAO implements FahrzeugDAO {

	private final String dateiname;

	public SerializedFahrzeugDAO(String dateiname) {
		this.dateiname = dateiname;

	}

	public void storeFahrzeuge(ArrayList<Fahrzeug> fahrzeuge) {

		try {
			ObjectOutputStream out = new ObjectOutputStream(
					new FileOutputStream(dateiname));

			out.writeObject(fahrzeuge);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public ArrayList<Fahrzeug> readFahrzeuge() {
		ArrayList<Fahrzeug> fahrzeuge = null;

		try {

			ObjectInputStream in = new ObjectInputStream(new FileInputStream(
					dateiname));
			fahrzeuge = (ArrayList<Fahrzeug>) in.readObject();

			in.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return fahrzeuge;
	}

}

und in der Klasse Fahrzeug habe ich so gemacht?
public abstract class Fahrzeug implements Serializable

Bin zwar nicht Marco, antworte aber trotzdem mal: Ja, so sollte es funktionieren. Wenn es hier um Lernen geht, denke bei dem Code nochmal über zwei Sachen nach:

  1. Stelle auf List um, statt der konkreten Implementierung ArrayList. Was müsste da im Code beachtet werden? (Tipp: das List-Interface garantiert nicht, dass Implementierungen Serializable sind)
  2. Ist das returnen von null bei Auftreten eines Fehlers wirklich gut? Was gäbe es für Alternativen?

EDIT: Kommando zurück:

Wie gesagt, statt
ArrayList
sollte da überall auch einfach
List
stehen können. Allgemein sollte man in solchen Fällen das Interface (hier „List“) verwenden, weil man dadurch flexibler für künftige Änderungen bleibt. (Allgemein sogar das „kleinste“ Interface, das die gewünschte Aufgabe erfüllt, auch wenn diese Aussage in diesem speziellen Fall für sich nicht viel Sinn macht :wink: )

Das ist so eigentlich sinnlos, weil man zumindest wissen muss, dass das Objekt „Serializable“ ist, deswegen wäre ArrayList da wohl OK (verwende Serialization nicht so oft aktiv).

Eindeutig Zeit für’s Wochenende :o

EDIT2: Ja, @nillehammer , das ist eben die interessante Frage: WENN man sowieso davon ausgehen muss, dass das Objekt Serializable ist - kann man dann nicht (NUR in diesem speziellen Fall!) DOCH wieder ArrayList als gerechtfertigt ansehen?

Man kann zwar einige nifty tricks machen, um auch für solche Fälle Typsicherheit zu erreichen,…

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

class TypesafeSample
{
    static void bar() throws IOException
    {
        ObjectOutputStream out = null;

        ArrayList<String> a = null;
        Vector<String> b = null;
        List<String> c = null;

        write(out, a); // Geht
        write(out, b); // Geht
        write(out, c); // Geht nicht
    }
    
    static <T extends List<String> & Serializable> void write(ObjectOutputStream out, T t) throws IOException
    {
        out.writeObject(t);
    }
}```

... aber das passt wohl nicht ganz hier her....

Die meisten Implementierungen einer List sind sowieso Serializable. Deshalb würde ich es so machen:
If Liste instanceof Serializable direkt in den ObjectOutputStream schreiben, falls nicht mit new ArrayList(andereListe) die Elemente in eine ArrayList kopieren und dann wegschreiben. Aber man kann es natürlich auch kompliziert machen :smiley:

[…]… aber das passt wohl nicht ganz hier her…

Und würde auch der API widersprechen. Am Ende will ich ja ein Interface, dass die Methoden mit List definiert und Implementierungen, die damit umgehen können. Da kommt eine zusätzliche Einschränkung der Liste auf Serializable nicht in Frage.

programmieren ist flustrierend

also ihr meint, dass ich in alle meine Klassen statt ArrayList List schreiben soll?
in der Methode storeFahrzeuge sollte ich wie @nillehammer gesagt hat if Überprüfung machen soll und in der else klammer von List Arraylist erzeugen und so in ObjectOutputStream schreiben?

Anni

also ihr meint, dass ich in alle meine Klassen statt ArrayList List schreiben soll?
in der Methode storeFahrzeuge sollte ich wie @nillehammer gesagt hat if Überprüfung machen soll und in der else klammer von List Arraylist erzeugen und so in ObjectOutputStream schreiben?

Prinzipiell ist es immer gut, den allgemeinst möglichen Typ für Parameter und Rückgabetypen zu nehmen. In dem Fall wäre List wirklich die bessere Wahl. Und ja, so würde ich es machen, also bei nicht Serializable List:
new ArrayList<>(fahrzeuge);

Der Sinn eines Interfaces ist der eines Vertrages. Zu sagen, dass “die meisten” Implementierungen Serializable sind, bringt nicht so viel. Man müßte/könnte sowas machen wie

    public class SerializedFahrzeugDAO implements FahrzeugDAO {
...     
        public void storeFahrzeuge(List<Fahrzeug> fahrzeuge) {
...
           if (fahrzeuge instanceof Serializable) { /* schreibe direkt in 'out' */
           else {
               out.writeObject(new ArrayList<Fahrzeug>(fahrzeuge));
           }
        }

        public List<Fahrzeug> readFahrzeuge() {
...
            List<Fahrzeug> fahrzeuge = (List<Fahrzeug>) in.readObject();
...
            return fahrzeuge;
        }
     
    }

Also, beim rausschreiben in einer neue ArrayList einwickeln, falls das nötig ist. Ist vielleicht gar nicht so verkehrt so, auch wenn der Nutzen des Interfaces hier deutlich weniger offensichtlich und schlagend ist, als in anderen Fällen.

Genau an so einen Code hatte ich gedacht. Und den Hinweis, dass die meisten Implementierungen Serializable sind, wollte ich so verstanden wissen, dass so ein Code nicht so schlecht ist, wie man auf den ersten Blick vielleicht denkt, weil der else-Fall nicht sehr oft auftreten wird.

Den Sinn der Nutzung des List-Interfaces sehe ich darin, dass man das Interface FahrzeugDAO so definieren würde. Bei anderen denkbaren Implementierungen (bspw. XMLDao, JPADao) ist es ja eher egal, ob die übergebene Liste Serializable ist. Und nur, weil die SerializedDAO-Implementierung das braucht, die ArrayList ins DAOInterface hochzuschieben wäre doch eine sehr starke Einschränkung.