Kolekcja i przekazanie referencji

0

Witam. Chciałbym aby funkcja getFromFile czytała z pliku obiekty będące listą i przypisywala je do kolejno zmiennych animals i employees.
Jednak skoro w javie nie ma przekazywania przez referencje, a przez wartość, to nie mam pomysłu co zrobić.


klasa Shelter

        List<Animal> animals2 = new ArrayList<>();
        List<Employee> employees2 = new ArrayList<>();
        FileWorker.getFromFile(animals2, employees2);
        animals2.forEach(a -> System.out.println(a));


klasa FileWorker

    static public void getFromFile(List<Animal> animals, List<Employee> employees) {
        try(ObjectInputStream os = new ObjectInputStream(new FileInputStream("shelterinfo.bin"))) {

                animals = (ArrayList<Animal>) os.readObject();
                employees = (ArrayList<Employee>) os.readObject();
        } catch (FileNotFoundException e) {
            System.out.println("Can not find the file");
        } catch (IOException e) {
            System.out.println("Can not read information from the file");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
1

Generalnie przez wartosc sa przekazywane prymitywy a bardziej zlozone obiekty przez referencje wlasnie

0

no właśnie chyba nie, skoro

        animals2.forEach(a -> System.out.println(a));

w klasie shelter nie daje nic, a umieszczone w FileWorker daje odpowiednie wyniki(takie jakie powinny byc)

1

Przekazana jest wartosc referencji, wiec moze utworz nowa referencje do odpowiedniej listy w FileWorker i przypisz do niej to co przyszlo

Edit: niewiele to zmieni bo dzialanie na parametrze tez dziala

1

W Javie referencje są przekazywane przez wartość. Może to dziwnie brzmieć, ale porównanie między C, a Javą powinno rozjaśnić sprawę (zakładając, że znasz C):

class Xxx {
  int a;
  byte[] bs;
}

void metoda(Xxx xxx) {
  xxx.a = 5;
  xxx = null; // to nie wpływa na 'xxx' z miejsca wywołania
}

Xxx xxx = new Xxx();
xxx.bs = new int[8];
metoda(xxx);

jest równa mniej więcej takiemu kodowi w C (z tym, że ma trochę błędów składniowych pewnie):

struct Xxx {
  int a;
  byte * bs;
}

void metoda(Xxx * xxx) {
  *xxx.a = 5;
  xxx = NULL; // to nie wpływa na 'xxx' z miejsca wywołania
}

Xxx * xxx = malloc(sizeof(Xxx));
*xxx.bs = malloc(sizeof(byte)*8);
metoda(xxx); // tu jak widzimy przekazujemy wskaźnik przez wartość
1

No czyli musisz albo operowac dalej na tym samym obiekcie (np. przeleciec petla nowy obiekt wczytany z pliku i kazdy element dodac do obiektu ktorego referencje dostales) albo w FileWorker zwrocic referencje do wczytanych obiektow i je przypisac w klasie Shelter do odpowiednich zmiennych

0

Dziękuje wam obu, zrozumiałem.
A da radę jakoś ładniej to zrobić np bez używania nowych zmiennych : List<Animal> newAnimals ?

            List<Animal> newAnimals = (ArrayList<Animal>)os.readObject();
            newAnimals.forEach(a->animals.add(a));

            List<Employee> newEmployees = (ArrayList<Employee>) os.readObject();
            newEmployees.forEach(e->employees.add(e));

a tu do C jakby ktos trafił na ten post ichciał odpalić działający kod, który przytoczył Wibowit


#include<stdio.h>
#include<stdlib.h>

struct A {
	int a;
	char * bs;
};

void metoda(struct A* xxx)
{
	xxx->a = 6;
        xxx = NULL;
}

int main()
{
	struct A * xxx =(struct A*) malloc(sizeof(struct  A));
	(*xxx).a = 5;
	metoda(xxx);
	printf("%d", xxx->a);
	return 0;
}
0

Ostateczna wersja jaką wykminiłem:

    static public void getFromFile(List<Animal> animals, List<Employee> employees) {
        try(ObjectInputStream os = new ObjectInputStream(new FileInputStream("shelterinfo.bin"))) {

            animals.addAll( (ArrayList<Animal>)os.readObject());
            employees.addAll((ArrayList<Employee>) os.readObject());

        } catch (FileNotFoundException e) {
            System.out.println("Can not find the file");
        } catch (IOException e) {
            System.out.println("Can not read information from the file");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


PS Która czytelniejsza, którą lepiej stosować?

1

Wydaje mi sie ze wydajniejsze bedzie zwrocenie referencji do obiektu niz przekopiowanie calosci do drugiego. Ale wtedy musisz zrobic dwie oddzielne metody do animals/employees i dwa rozne pliki. No ale zdaje sie to tez byc logiczniejsze niz trzymac dwa niezalezne obiekty w jednym pliku i za pomoca jednej metody

Edit: albo generator

1
stivens napisał(a):

Wydaje mi sie ze wydajniejsze bedzie zwrocenie referencji do obiektu niz przekopiowanie calosci do drugiego. ....

Patrząc na ten konkretny przypadek, rzuca się pytanie**: cooooo **? Co i jak wydajniesjsze? I czy autor rzeczywiście ma ten kod umieszczony w krytycznym kawałku do sterowania pralką frania, że musi być naprawdę wydajne.

Technicznie metoda, która bierze jako parametry jakieś listy, a potem je modyfikuje (dopisuje) to:

  1. normalna sprawa w Javie,
  2. jest błędogenna, łatwo przeoczyć co kto gdzieś modyfikuje

Najlepiej jak metoda nie jest void tylko zwraca wynik.
Tutaj najlprościej jak byś miał dwie metody.

  1. Otwierasz plik.
  2. Wywołujesz readAnimals (podając ObjectInputStream jako prametr)
  3. Wywołujesz readEmployess (podając ObjectInputStream jako prametr)
  4. TADAAAM!

Można jeszcze zrobić jedną metodą, która zwraca obie listy:
skorzystać z Vavr [Tuple] (https://static.javadoc.io/io.vavr/vavr/0.9.0/io/vavr/Tuple2.html)

Tuple2<Lst<Animal>, List<Employee>>  readThemAll() {



Albo wprowadzic własna klasę pomocniczą

class MyObjects
public final List<Animal> animals;
public final List<Employee> employees;
MyObjects(List<Animal> animals, List<Employee> employees () ) {
        this.animals = animals;
        this.employees = employees;   
} 

Wydajność wszystkich tych rozwiązań (również z poprzednich postów) jest praktycznie taka sama - i tak najwiecej trwa czytanie z pliku.

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