NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Volání objektu na objekt

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Patrik Marýška:19.1.2018 10:40

Ahoj,
chtěl bych poprosit o radu.

public class LinkedList {

    private Node first;
    private Node last;
    private int size;

    public LinkedList() {
        this.size = 0;
    }

    /**
     * Vlozi prvek na konec seznamu
     * @param i prvek k vlozeni
     */
    public void insert(int i) {
        Node n = new Node(i);
        if (size == 0) {
            this.first = n;
            this.last = n;
        } else {
            this.last.next = n;
            this.last = n;
        }
        size++;
    }

    /**
     * Vrati prvek na indexu i
     * @return prvek na indexu i
     */
    public int read(int i) {
        if (i >= size) {
            throw new IndexOutOfBoundsException("Mimo meze index:" + i + ", size:" + this.size);
        }
        if (i < 0) {
            throw new IllegalArgumentException("Index mensi nez 0");
        }
        Node curr = first;
        for (int j = 0; j < i; j++) {
            curr = curr.next;
        }
        return curr.value;
    }

    /**
     * Smaze prvek na indexu i
     * @param i index mazaneho prvku
     */
    public void delete(int i) {
        if (i >= size) {
            throw new IndexOutOfBoundsException("Mimo meze index:" + i + ", size:" + this.size);
        }
        if (i < 0) {
            throw new IllegalArgumentException("Index mensi nez 0");
        }
        if (i == 0) {
            first = first.next;
        } else {
            Node curr = first;
            for (int j = 0; j < i - 1; j++) { //najdeme predchozi
                curr = curr.next;
            }
            curr.next = curr.next.next; //a mazany prvek vynechame
            if (i == size - 1) { //pokud mazeme posledni
                last = curr;
            }
        }
        size--;
    }

    /**
     * Delka seznamu
     * @return delka seznamu
     */
    public int size() {
        return this.size;
    }

    /**
     * Klasicka toString metoda, vraci textovou reprezentaci objektu
     * @return textova reprezentace objektu
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        Node curr = first;
        for (int i = 0; i < this.size; i++) {
            builder.append(curr.value).append(" ");
            curr = curr.next;
        }
        return builder.toString();
    }

    /**
     * Vnitrni trida reprezentujici uzel spojoveho seznamu
     */
    private class Node {

        private int value;
        private Node next;

        private Node(int value) {
            this.value = value;
        }
    }
}

Nedaří se mi úplně porozumět, jak se tento kod chová...
Například:

this.last.next = n;

Jak mohu volat na objekt další objekt? (který není ani inicializovaný)
V podstatě jakákoliv část kodu, kde se volá .next mi dělá potíž a nechápu, jak to funguje a co to pořádně dělá a jak to dělá...
Mohl bych poprosit, zda by mi to někdo mohl osvětlit?

Mockrát děkuji

 
Odpovědět
19.1.2018 10:40
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:19.1.2018 11:28

No očividně jsi se učil na zdejších tutoriálech viď?:(
A přesně, co jsem tolikrát tak často zmiňoval - tyto stránky jsou perfektní, ale tutoriál na Javu naprosto ignoruje zapouzdření a taky ten kód tak šíleně vypadá:(

Metoda Insert asi podle názvu bude vkládat prvky do seznamu. Předpokládám, že třída Node reprezentuje 1 položku ze seznamu, která si jen pamatuje nějakou hodnotu a odkaz na další položku. (tady bych se trošku zamyslel nad logikou aplikace - asi by bylo možná lepší předávat jako parametr v metodě insert přímo objekt Node). Když se přidává do seznamu položka, tak seznam vyžaduje, aby každý Node měl současně odkaz na svojeho "následníka". Takže když přidáváš Noda, tak si vezmeš poslední Node v seznamu (je v atributu last), přidáš tomuto Nodovi toho nového Noda, (prostě last.next zavolá atribut toho posledního noda, jde to tak, ale je to čuňárna). A ten nový Node nastavíš jako last, takže při příštím vkládání bude on ten, kdo si přidá nového noda.

A toto je právě to, o čem jsem mluvil na začátku. Je to svinstvo a rozhodně to není čisté OOP programování. Jde to, ale porušuje to zapouzdření. Princip zapouzdření spočívá v tom, že by žádný jiný objekt neměl přistupovat přímo k atributům jiného objektu. Proto existují tzv. přístupové metody (access methods) známé taky jako settry a gettry. Pokud chceš aby měl "zbytek světa" přístup k atributům třídy, tak pro nastavování tohoto atributu použij metodu setNazevAtribu­tu(parametr) a pro získání tohoto parametru použij metodu getNazevAtributu(). Dřív to byla pouze zavedená konvence,
dneska je to naprostý standart. (a dokonce dnešní IDEčka už umožňují vygenerovat přímo settry, gettry nebo současně i settry a gettry u vybraných parametrů)

Samozřejmě - jak vidíš, tak to jde i bez zapouzdření, ale vzniká velké nebezpečí a navíc ten kód vypadá strašně.

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
19.1.2018 11:28
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:19.1.2018 11:29
this.last.next = n;

Jak mohu volat na objekt další objekt? (který není ani inicializovaný)

Nevoláš tedy objekt na objekt, ale voláš atribut objektu. Buď tečkou můžeš volat metody (a to bys měl v OOP pouze a jenom) a nebo volat atribut této třídy.

Nahoru Odpovědět
19.1.2018 11:29
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Patrik Marýška:19.1.2018 11:49

Mockrát děkuji :). Tenhle kod není psaný mnou, právě proto mě to dost zmátlo, protože jsem se s tímhle způsobem volání atributu nesetkal. Gettery/settery používám běžně, ale nenapadlo mě, že to lze pomocí toho tady přepsat.:)

 
Nahoru Odpovědět
19.1.2018 11:49
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:19.1.2018 11:54

dobrý, tak se to tak ani neuč:D

Nahoru Odpovědět
19.1.2018 11:54
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Petr
Člen
Avatar
Odpovídá na Lubor Pešek
Petr:19.1.2018 17:06

Primy pristup k atributum tridy Node v tomto pripade neni porusenim principu zapouzdreni, protoze trida Node je privatni a tedy viditelna jen v ramci implementace tridy LinkedList. Kdyz se treba podivas na implementaci LinkedList v JDK 8 tak to delaji uplne stejnym zpusobem, jen je Node genericky.
Pouzivat tridu Node jako parametr metody insert je taky spatny napad, protoze tim by jsi vystavil vnitrni implementaci vazeb linked listu vsem kdo pouzivaji dany linked list. Kdokoli by mohl rozbit vazby v tom linked listu. Vystaveni tridy Node by bylo prave poruseni zapouzdreni tridy LinkedList.
Na tridu Node v tomto konkretnim pripade se nelze divat jako na klasickou java tridu. V tomto pripade se jedna spise o interni datovou strukturu jine tridy. Samozrejme syntakticky to trida je, protoze java nema nic jako datove struktury.

 
Nahoru Odpovědět
19.1.2018 17:06
Avatar
gcx11
Tvůrce
Avatar
Odpovídá na Lubor Pešek
gcx11:19.1.2018 19:19

Co si myslíš, že je lepší?

player.addExperience(42);

anebo

player.setExperience(player.getExperience() + 42);
 
Nahoru Odpovědět
19.1.2018 19:19
Avatar
Odpovídá na Patrik Marýška
Robert Michalovič:19.1.2018 19:48
this.last.next = n;

Ale je inicializovaný.

  1. Vytvoříš objekt LinkedList což znamená, že se zavolá konstruktor
  2. V konstruktoru vidíš this.size = 0; což znamená že proměnná size je nyní rovna nule
  3. pokud voláš metodu insert, jako první se vytvoří objekt Node a po něm dochází k porovnávací logice
if (size == 0)

protože jsme v konstruktoru definovaly size = 0 tak vždy první porovnání(vyhod­nocení) if končí true co vede k cyklu kdy se tvz. přiřadí reference privatním proměnným first a last třídy LinkedList.

 if (size == 0) {
            this.first = n;
            this.last = n;
}

A na konci metody insert zvýšíš proměnou size o 1.

size++;
  1. poté co znova zavoláš metodu insert pak již proměnná size není roven nule a volá se tato část cyklu kde se objektu last přidá jako proměnná další objekt Node. ( tvz. pouze objekt v objektu )
else {
            this.last.next = n;
            this.last = n;
     }

takže vidíš že last je inicializovaný a tudíž k jeho proměnné lze přistupovat a provést nastavení.

 
Nahoru Odpovědět
19.1.2018 19:48
Avatar
Odpovídá na gcx11
Štefan Melich:19.1.2018 21:48

Prvá možnosť je síce zrozumiteľnejšia a prehľadnejšia, ale java "style" je ten druhý prípad.

Editováno 19.1.2018 21:49
 
Nahoru Odpovědět
19.1.2018 21:48
Avatar
Lubor Pešek
Člen
Avatar
Odpovídá na gcx11
Lubor Pešek:20.1.2018 11:29

trošku nechápu tvůj dotaz, protože to máš dva rozdílné výsledky....

player.addExperience(42);

ti nastaví hodnotu na 42

player.setExperience(player.getExperience() + 42);

ti zvýší aktuální hodnotu o 42.... Nechápu co to má společného s tímto ticketem a už vůbec s tím, co jsem psal já....

Nahoru Odpovědět
20.1.2018 11:29
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.