readObject i metoda instanceof

0

Witam miałem napisać program do zarządzania pracownikami. Napisałem bez problemu, zapis i odczyt odbywał się z i do pliku txt przez BufferedReader i BufferedWriter. Teraz prowadzący zażyczył sobie zrobienie odczytu za pomocą Serializable o ile nie mam problemu z zapisem i odczytem (bezpośrednim do danego typu) to nie mogę sobie poradzić z polimorfizmem mam klasę abstrakcyjną Pracownik i rozszerzam ją o klasy Administracyjny oraz Dydaktyczny wszystkie dane muszę przechowywać w tablicach oprócz wyniku wyszukiwania. Gdy próbuję to skompilować to dostaję taki błąd
Exception in thread "main" java.lang.NullPointerException at Operacje.wypiszWszystkich(Operacje.java:125) at Test.main(Test.java:76) podejrzewam że tablica jest pusta bo nie działa odczyt, moglibyście mi pomóc jak go wykonać

 import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

public class Operacje implements Serializable{
	
	ArrayList <Pracownik> result=new ArrayList<Pracownik>();
	public Pracownik workers[];
	private int amount;
	public Operacje(){
		int amount=0;
		byte a=0;
		try{
			ObjectInputStream s=new ObjectInputStream(new FileInputStream("Database.ur"));
			amount=s.readInt();
			this.amount=amount;
			workers=new Pracownik[amount];
			Object worker=null;
			for (int i=0;i<amount;i++){
				worker=s.readObject();
				if(worker instanceof Admnistracyjny){
				workers[i]=new Admnistracyjny("","",a,"",0,"");
				workers[i]=(Admnistracyjny)worker;
				
				}
			if(worker instanceof Dydaktyczny){
				workers[i]=new Dydaktyczny("","",a,"",0,"");
				workers[i]=(Dydaktyczny)worker;
				}
			}
			
			s.close();
			
		}catch(Exception e){
			
		}	
	}
		
	
	public  void Search (String type,String value){
		result.clear();
		if (type.equals("zarobki")){
			int ernings=new Integer(value);
			for (int i=0;i<workers.length;i++){
				if(workers[i].getEarnings()==ernings){
					result.add(workers[i]);
				}
			}
		}
		
		else if (type.equals("nazwisko")){
			for (int i=0;i<workers.length;i++){
				if(workers[i].getSurname().equals(value)){
					result.add(workers[i]);
				}
			}
		}
		
		else if(type.equals("pesel")){
			for (int i=0;i<workers.length;i++){
				if(workers[i].getPesel().equals(value)){
					result.add(workers[i]);
				}
			}
		}
		
		else if (type.equals("stanowisko")){
			for (int i=0;i<workers.length;i++){
				if(((workers[i] instanceof Admnistracyjny) && (((Admnistracyjny)workers[i])).getPost().equals(value))){
					result.add(workers[i]);
				}
		}
		}
		
		else if (type.equals("przedmiot")){
			for (int i=0;i<workers.length;i++){
				if(((workers[i] instanceof Dydaktyczny) && (((Dydaktyczny)workers[i])).getSubject().equals(value))){
					result.add(workers[i]);
				}
		}
		}
	}
	
	
	public void SaveFile(Pracownik tab1[]) throws FileNotFoundException{
		try{
			ObjectOutputStream save=new ObjectOutputStream(new FileOutputStream("Database.ur"));
			int suma=((tab1.length+workers.length));
			save.writeInt(suma);
			for (int i=0;i<suma;i++){
				if (i<workers.length){
					save.writeObject(workers[i]);
				}
				else{
					save.writeObject(tab1[i-workers.length]);
				}
			}
			save.close();
		}
		catch(Exception e){
			
		}


		System.out.println("Zapisano");
	}
	
	
	public void Output(){
		if(result.isEmpty()){
			System.out.println("Brak pracowników o danych parametrach");
		}
		else{
			for(Pracownik p:result){
				System.out.println(p.toString());
			}
		}
	}
	public void wypiszWszystkich(){
		for (int i=0;i<amount;i++){
			System.out.println(workers[i].toString());
		}
	}
}

1
Masterpc96 napisał(a):

Najprościej to przy zapisywaniu i odczytywaniu z pliku nie baw sie w jakies instanceof i zapisywanie ilości - tylko zapisz całą tablicę jednym strzałem:

public Pracownik workers[];

..//
save.writeObject(workers);
//

Odczyt analogicznie:

workers=( Pracownik[]) s.readObject();
0

a powiedz mi zapis jak się odbywa w tym Serializable tak jak w txt otwiera mi plik i go czyści i wpisuje na nowo?

0

Skąd Twoje przekonanie, że "czyści i wpisuje na nowo"? To zależy jak utworzysz FileWriter czy te FileOutputStream. Możesz otworzyć do dopisywania: https://docs.oracle.com/javase/8/docs/api/java/io/FileOutputStream.html

0

czyli działanie takie samo jak w zapise np. PrintWriter domyślnie otwiera i czyści ale jak ustawię na dopisywanie to początek zostawi i kursor ustawi na końcu?

1

Hej,

Klasa Operacje nie musi być Serializable. Nie wiadomo po co jest. Pracownik musi być.

Wtedy saveFile tak jak Jarek napisał, jak chcesz pojedynczo zapisywać to też możesz: w pętli i dla każdego obiektu typu Pracownik wykonujesz writeObject.
Za każdym razem plik jest nadpisywany (czyszczony). W ogóle jakąś dziwną logikę masz w tym saveFile. Niepotrzebna.

Nie musisz zapisywać amount - jak wczytasz wszystkie to będziesz wiedzieć ile masz.

Nie rób catch(Exception e), tylko rzucaj dalej.
Nazwy metod zaczynamy małą literą.

Jak chcesz robić nadpisywanie pliku to użyj FileOutputstream(String filename, boolean append).

Ale najpierw przetestuje czy działa z wymazywaniem pliku, a potem kombinuj z dopisywaniem (jezeli jest to w ogóle konieczne).

I używaj debuggera, będziesz wiedzieć co się dzieje i dlaczego.

/pozdr

0
krgr napisał(a):

Jak chcesz robić nadpisywanie pliku to użyj FileOutputstream(String filename, boolean append).
[/quote]

Chyba dopisywanie ;)

Dzięki za wyczerpującą odpowiedź ;)
Nie wiem czemu czasami nazwy metod pisałem z dużej litery, a zapoznałem się z konwencją nazewnictwa.

0

dobra poprawiłem to trochę

 import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
 
public class Operacje{
 
    ArrayList <Pracownik> result=new ArrayList<Pracownik>();
    public Pracownik workers[]=null;
    public Operacje(){
        try{
            ObjectInputStream s=new ObjectInputStream(new FileInputStream("Database.ur"));
            workers=(Pracownik[])s.readObject();
            s.close();
        }catch(Exception e){
        		System.out.println(e.getMessage());
        }   
    }
 
    public  void search (String type,String value){
        result.clear();
        if (type.equals("zarobki")){
            int ernings=new Integer(value);
            for (int i=0;i<workers.length;i++){
                if(workers[i].getEarnings()==ernings){
                    result.add(workers[i]);
                }
            }
        }
 
        else if (type.equals("nazwisko")){
            for (int i=0;i<workers.length;i++){
                if(workers[i].getSurname().equals(value)){
                    result.add(workers[i]);
                }
            }
        }
 
        else if(type.equals("pesel")){
            for (int i=0;i<workers.length;i++){
                if(workers[i].getPesel().equals(value)){
                    result.add(workers[i]);
                }
            }
        }
 
        else if (type.equals("stanowisko")){
            for (int i=0;i<workers.length;i++){
                if(((workers[i] instanceof Admnistracyjny) && (((Admnistracyjny)workers[i])).getPost().equals(value))){
                    result.add(workers[i]);
                }
        }
        }
 
        else if (type.equals("przedmiot")){
            for (int i=0;i<workers.length;i++){
                if(((workers[i] instanceof Dydaktyczny) && (((Dydaktyczny)workers[i])).getSubject().equals(value))){
                    result.add(workers[i]);
                }
        }
        }
    }
 
    public void saveFile(Pracownik tab1[]) throws FileNotFoundException{
    	Pracownik[] allWorkers=new Pracownik[(tab1.length+workers.length)];
    	System.arraycopy(workers, 0, allWorkers, 0, workers.length);
    	System.arraycopy(tab1, 0, allWorkers, workers.length, tab1.length);
        try{
            ObjectOutputStream save=new ObjectOutputStream(new FileOutputStream("Database.ur"));
            save.writeObject(allWorkers);
            save.close();
        }
        catch(Exception e){
 
        }
 
        System.out.println("Zapisano");
    }
 
    public void output(){
        if(result.isEmpty()){
            System.out.println("Brak pracowników o danych parametrach");
        }
        else{
            for(Pracownik p:result){
                System.out.println(p.toString());
            }
        }
    }
    public void wypiszWszystkich(){
        for (int i=0;i<workers.length;i++){
            System.out.println(workers[i].toString);
        }
    }
}

dziedziczenie mam w ten sposób Pracownik (implementuje Serializable) po nim dziedziczy Administracyjny i Naukowy (już nie implementują Serializable)
Mam przygotowaną tablicę z jednym pracownikiem, wywala mi błąd na odczycie tablicy Admnistracyjny; no valid constructor w debugerze pokazuje że jest ona pusta

1

Te trzy linijki to wywal - nie wiem co chciałeś uzyskać - ale niepotrzebne są ( i raczej zrypane):

     Pracownik[] allWorkers=new Pracownik[(tab1.length+workers.length)];
        System.arraycopy(workers, 0, allWorkers, 0, workers.length);
        System.arraycopy(tab1, 0, allWorkers, workers.length, tab1.length);

Dla pewności wywal stare zapisane 'Database.ur'. może masz tam jakieś śmieci.

A jak nie zadziała - to nie wstydź się -> pokaż tego stack trace całego - oraz klasy Administracyjny i Naukowy (nie chce mi się zgadywać co tam masz).

Poprawka - chyba wiem co chciałeś uzyskać:
Więc zmień metodę save na taką:

  public void saveFile(Pracownik tab1[]) throws IOException{
        Pracownik[] allWorkers=new Pracownik[(tab1.length+workers.length)];
        System.arraycopy(workers, 0, allWorkers, 0, workers.length);
        System.arraycopy(tab1, 0, allWorkers, workers.length, tab1.length);

       workers = allWorkers;
            ObjectOutputStream save=new ObjectOutputStream(new FileOutputStream("Database.ur"));
            save.writeObject(workers);
            save.close();
 
        System.out.println("Zapisano");
    }
    
0

Wywaliłem dane zapisałem pracownika na nowo do pustego pliku nie działa tylko odczyt
klasa pracownik administracyjny

 
public class Admnistracyjny extends Pracownik{
	private String post;
	public Admnistracyjny (String name, String surname, byte age, String pesel, int earnings,String post){
		super(name,surname,age,pesel,earnings);
		this.post=post;
	}
	
	public String getPost(){return post;}
	
	public String toString(){
		return(super.toString()+ " " + getPost());
	}
}

Klasa pracownik Dydaktyczny

 
public class Dydaktyczny extends Pracownik{
	private String subject;
	public Dydaktyczny (String name, String surname, byte age, String pesel, int earnings,String subject){
		super(name,surname,age,pesel,earnings);
		this.subject=subject;
	}
	
	public String getSubject(){return subject;}
	
	public String toString(){
		return(super.toString()+ " " + getSubject());
	}
}

Klasa Pracownik

 import java.io.Serializable;

abstract public class Pracownik extends Osoba implements Serializable{
	private int earnings;
	public Pracownik (String name, String surname, byte age, String pesel, int earnings){
		super (name, surname, age, pesel);
		this.earnings=earnings;
	}
	
	int getEarnings(){return earnings;}
	
	public String toString(){
		return(getName() + " " + getSurname() + " " + getAge() + " " + getPesel() + " " + getEarnings());
	}
}

jeszcze klasa Osoba

 public abstract class Osoba {
	private String name,surname, pesel;
	private byte age;
	public Osoba(String name, String surname, byte age, String pesel){
		this.name=name;
		this.surname=surname;
		this.age=age;
		this.pesel=pesel;
	}
	String getName(){return name;}
	String getSurname(){return surname;}
	String getPesel(){return pesel;}
	byte getAge(){return age;}
	
}

Exception in thread "main" java.lang.NullPointerException at Operacje.wypiszWszystkich(Operacje.java:90) at Test.main(Test.java:76)
Pokazuje na linijkę wypisania

 System.out.println(workers[i].toString);

Ps chodzi o to ?

0
Masterpc96 napisał(a):
 System.out.println(workers[i].toString);

Ps chodzi o to ?

Tak.
Nie widze błędu - ale możesz trochę sobie pomóc używając debugera.
Trzeba sprawdzić co jest przez zapisem w workers, i co jest po odczycie.

Możesz to tez zrobić wypisując na konsole.
System.out.println(Arrays.toString(this.workers));
Zrób to przed writeObject i po readObject - powinno coś być widać.

(Ogólnie to strzelam (bo nie widzę oczywistego błędu w podanym przez Ciebie kodzie), że możesz mieć błąd w Test.java)

0

Zapis jest prawidłowy
EDIT

 public void saveFile(Pracownik tab1[]) throws IOException{
        //Pracownik[] allWorkers=new Pracownik[(tab1.length+workers.length)];
        //System.arraycopy(workers, 0, allWorkers, 0, workers.length);
        //System.arraycopy(tab1, 0, allWorkers, workers.length, tab1.length);

       workers = tab1;
       for (int i=0;i<workers.length;i++){
           System.out.println(workers[i].toString());
       }

            ObjectOutputStream save=new ObjectOutputStream(new FileOutputStream("Database.ur"));
            save.writeObject(workers);
            save.close();

        System.out.println("Zapisano");
    }
 
    public void output(){
        if(result.isEmpty()){
            System.out.println("Brak pracowników o danych parametrach");
        }
        else{
            for(Pracownik p:result){
                System.out.println(p.toString());
            }
        }
    }

wybierz cyfrę

  1. Szukaj pracownika
  2. Dodaj pracownika
  3. Wypisz wszystkich
    2
    Admnistracyjny; no valid constructor
    Podaj typ pracownika jaki chcesz dodać
    1.Administracyjny
    2.Dydaktyczny
    1
    Ilu chcesz dodać pracowników
    1
    Podaj dane pracownika w tym formacie
    imię;nazwisko;wiek;pesel;zarobki;dział
    Jan;Kowalski;55;58959665;5500;kadry // to podaję ja
    Jan Kowalski 55 58959665 5500 kadry // to wyświetla
    Zapisano

A błędem nie jest to że Administracyjny i Dydaktyczny mają konstruktor ze średnikami bo tak rozdziela dane podane przeze mnie a w zapisie w tablicy nie mam tych średników i w odczycie wywala błąd?

1
Masterpc96 napisał(a):

A błędem nie jest to że Administracyjny i Dydaktyczny mają konstruktor ze średnikami bo tak rozdziela dane podane przeze mnie a w zapisie w tablicy nie mam tych średników i w odczycie wywala błąd?

Nie. ( Nie do końca wiem o czym piszesz :-), ale to raczej nie jest problem).

Wróżka modde. Zgaduję - Błąd masz w tym, że wywołując saveFile podajesz tablicę, która jest np. długości 10, a ma wypełnioną tylko 1 pozycję.

0

Tu mam wywołanie metody saveFile

 else if(choice==2){
			int amount=0;
			byte type=0;
			String s1;
			String s2[]= new String[6];	
			System.out.println("Podaj typ pracownika jaki chcesz dodać\n1.Administracyjny\n2.Dydaktyczny");
			type=s.nextByte();
			System.out.println("Ilu chcesz dodać pracowników");
			amount=s.nextInt();
			Pracownik workersH[]=new Pracownik[amount];
			
			if (type==1){
				System.out.println("Podaj dane pracownika w tym formacie\nimię;nazwisko;wiek;pesel;zarobki;dział");
				for (int i=0;i<amount;i++){			
					BufferedReader we=new BufferedReader(new InputStreamReader(System.in));
					try{
						s1=we.readLine();
						if ((s1!=null) || (!s1.equals(""))){
							s2=s1.split(";");
						}
					}catch (IOException e){
						e.printStackTrace();
					}
					workersH[i]=new Admnistracyjny(s2[0].trim(),s2[1].trim(),new Byte(s2[2].trim()),s2[3].trim(),new Integer(s2[4].trim()),s2[5].trim());				
			}
				
			}
			
			else if(type==2){
				System.out.println("Podaj dane pracownika w tym formacie\nimię;nazwisko;wiek;pesel;zarobki;przedmiot");
				for (int i=0;i<amount;i++){			
					BufferedReader we=new BufferedReader(new InputStreamReader(System.in));
					try{
						s1=we.readLine();
						if ((s1!=null) || (!s1.equals(""))){
							s2=s1.split(";");
						}
					}catch (IOException e){
						e.printStackTrace();
					}
					workersH[i]=new Dydaktyczny(s2[0].trim(),s2[1].trim(),new Byte(s2[2].trim()),s2[3].trim(),new Integer(s2[4].trim()),s2[5].trim());				
			}
			}
			
			task.saveFile(workersH);
		}

Nuli nie powinno być bo jak odczytuję całą tablicę forem to jest tylko ten jeden rekord

0

to wywala komunikat z ClassNotFoundException

 public Operacje() throws IOException, ClassNotFoundException{
            ObjectInputStream s=new ObjectInputStream(new FileInputStream("Database.ur"));
            workers=(Pracownik[])s.readObject();
            for(int i=0;i<workers.length;i++){
            	System.out.println(workers[i]);
            }
            s.close();  
    }

Exception in thread "main" java.io.InvalidClassException: Admnistracyjny; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:790)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1782)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1714)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at Operacje.<init>(Operacje.java:14)
at Test.main(Test.java:15)

Te błędu dotyczą tylko i wyłącznie odczytu

2

Dobra - chyba już wiem :

zmień tak klasę Osoba
public abstract class Osoba implements Serializable

A pokonała Cie kiepska obsługa Exceptionów. Nie rób nigdy catch( Exception e) jeśli nie musisz

0

Już zmieniam, w klasie Pracownik już nie muszę implementować Serializable? Czy Exception e wyłapuje najogólniejszy wyjątek?

0

jak zostawię Serializable tylko w klasie osoba to wywala ten błąd
Exception in thread "main" java.io.InvalidClassException: Pracownik; local class incompatible: stream classdesc serialVersionUID = 4643746275836876983, local class serialVersionUID = 8358143979088759527
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1714)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at Operacje.<init>(Operacje.java:14)
at Test.main(Test.java:15)

A jak w klasie pracowników również będzie zaimplementowany to działa prawie dobrze bo na imię i nazwiko (tylko) wypisuje null ale to zaraz poprawię

Ps. Dzięki za pomoc :D
EDIT

Musiałem na nowo utworzyć plik gdy interface jest zaimplementowany w Osoba
Jeszcze raz WIELKIE DZIĘKI :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1