Kolekcja i przekazanie referencji

Kolekcja i przekazanie referencji
macias_98
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 19
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ć.

Kopiuj

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();
        }
    }
stivens
  • Rejestracja: dni
  • Ostatnio: dni
1

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

macias_98
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 19
0

no właśnie chyba nie, skoro

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

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

stivens
  • Rejestracja: dni
  • Ostatnio: dni
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

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
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):

Kopiuj
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):

Kopiuj
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ść
stivens
  • Rejestracja: dni
  • Ostatnio: dni
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

macias_98
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 19
0

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

Kopiuj
            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

Kopiuj

#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;
}
macias_98
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 19
0

Ostateczna wersja jaką wykminiłem:

Kopiuj
    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ć?

stivens
  • Rejestracja: dni
  • Ostatnio: dni
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

jarekr000000
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: U krasnoludów - pod górą
  • Postów: 4730
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)

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



Albo wprowadzic własna klasę pomocniczą

Kopiuj
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.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.