Pouze tento týden sleva až 80 % na e-learning týkající se PHP. A zároveň využij akce až 30 % zdarma při nákupu e-learningu. Více informací.
Hledáme asistenty pro kurzy programování - pohodová brigáda. Více info
PHP week
Avatar
Milan
Člen
Avatar
Milan:19.8.2020 6:49

Ahoj, snažím se pochopit jak správně fungují reference na instance objektu. Vycházím z řešeného úkolu č. 4 - středně pokročilý případ a moc nerozumím jak ty reference fungují, pokusím se popsat čemu přesně nerozumím, snad bude někdo ochotný mi vysvětlit co se tam přesně děje. DĚKUJI!

V podstatě je úkol o procházení nějakých na sebe navázaných lokací.

Zkusil jsem: nahodím sem řešení celého úkolu

package prochazeni;

import java.util.Scanner;

public class Prochazeni {


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in, "Windows-1250");
        Hra hra = new Hra();
        String prikaz = "";

        // Hlavní smyčka hry
        while (!prikaz.equalsIgnoreCase("konec"))
        {
            System.out.println(hra.vratAktualniLokaci());
            System.out.println("Zadej příkaz: ");
            prikaz = sc.nextLine();
            hra.zpracujPrikaz(prikaz);
        }
    }

}
package prochazeni;

public class Lokace {
    /**
     * Lokace na severu
     */
    public Lokace sever;
    /**
     * Lokace na jihu
     */
    public Lokace jih;
    /**
     * Lokace na západě
     */
    public Lokace zapad;
    /**
     * Lokace na východě
     */
    public Lokace vychod;
    /**
     * Název lokace
     */
    private String nazev;
    /**
     * Dlouhý popis lokace
     */
    private String popis;

    /**
     * Inicializuje novou instanci
     * @param nazev Název lokace
     * @param popis Dlouhý popis
     */
    public Lokace(String nazev, String popis)
    {
        this.nazev = nazev;
        this.popis = popis;
    }

    /**
     * Vrátí textovou reprezentaci lokace
     * @return Textová reprezentaci lokace
     */
    @Override
    public String toString()
    {
        String vystup = nazev + "\n";
        vystup += popis + "\n\n";
        String smery = "";
        if (sever != null)
            smery += "sever ";
        if (jih != null)
            smery += "jih ";
        if (zapad != null)
            smery += "západ ";
        if (vychod != null)
            smery += "východ ";
        if (!smery.equals(""))
            vystup += "Můžeš jít na " + smery + "\n";
        return vystup;
    }
}
package prochazeni;

public class Hra {

    /**
     * Aktuální lokace
     */
    private Lokace aktualniLokace;

    /**
     * Vytvoří herní svět
     */
    public Hra()
    {
        // Vytvoření lokací
        Lokace hrad = new Lokace("Hrad", "Stojíš před okovanou branou gotického hradu, která je zřejmě jediným vchodem do pevnosti.\nKlíčová dírka je pokryta pavučinami, což vzbuzuje dojem, že je budova opuštěná.");
        Lokace les1 = new Lokace("Les", "Jsi na lesní cestě, která se klikatí až za obzor, kde mizí v siluetě zapadajícího\nslunce. Ticho podvečerního lesa občas přeruší zpěv posledních ptáků.");
        Lokace les2 = new Lokace("Lesní rozcestí", "Nacházíš se na lesním rozcestí.");
        Lokace les3 = new Lokace("Les", "Jsi na lesní cestě, která se klikatí až za obzor, kde mizí v siluetě zapadajícího\nslunce. Ticho podvečerního lesa občas přeruší zpěv posledních ptáků.");
        Lokace rybnik = new Lokace("Rybník", "Došel jsi ke břehu malého rybníka. Hladina je v bezvětří jako zrcadlo. Kousek\nod tebe je dřevěná plošina se stavidlem.");
        Lokace les4 = new Lokace("Les", "Jsi na lesní cestě, která se klikatí až za obzor, kde mizí v siluetě zapadajícího\nslunce. Ticho podvečerního lesa občas přeruší zpěv posledních ptáků.");
        Lokace dum = new Lokace("Dům", "Stojíš před svým rodným domem, citíš vůni čerstvě nasekaného dřeva, která se line\nz hromady vedle vstupních dvěří.");
        // Propojení lokací
        hrad.vychod = les1;
        les1.zapad = hrad;
        les1.vychod = les2;
        les2.zapad = les1;
        les2.vychod = les3;
        les2.jih = les4;
        les3.zapad = les2;
        les3.vychod = rybnik;
        rybnik.zapad = les3;
        les4.sever = les2;
        les4.vychod = dum;
        dum.zapad = les4;
        // Uložení aktuální lokace
        aktualniLokace = dum;
    }

    /**
     * Zpracuje textový příkaz
     * @param prikaz Příkaz
     */
    public void zpracujPrikaz(String prikaz)
    {
        prikaz = prikaz.toLowerCase();
        if (prikaz.startsWith("jdi"))
        {
            if (prikaz.endsWith("sever") && (aktualniLokace.sever != null))
                aktualniLokace = aktualniLokace.sever;
            else if (prikaz.endsWith("jih") && (aktualniLokace.jih != null))
                aktualniLokace = aktualniLokace.jih;
            else if (prikaz.endsWith("západ") && (aktualniLokace.zapad != null))
                aktualniLokace = aktualniLokace.zapad;
            else if (prikaz.endsWith("východ") && (aktualniLokace.vychod != null))
                aktualniLokace = aktualniLokace.vychod;
            else
                System.out.println("Tímto směrem nelze jít.");
        }
        else if (!prikaz.equals("konec"))
        {
            System.out.println("Můj vstupní slovník neobsahuje tento příkaz.");
        }
    }

    /**
     * Vrátí aktuální lokaci
     * @return Aktuální lokace
     */
    public Lokace vratAktualniLokaci()
    {
        return aktualniLokace;
    }

}

Chci docílit: Popíšu jak jsem to pochopil a potřeboval bych to potvrdit, případně ujasnit.

  1. při vytvoření tříd lokace si vytvořím reference na instanci - tedy světové strany
public Lokace sever
  1. v třídě hra se vytvoří objekty jednotlivých míst
Lokace hrad = new Lokace("Hrad", "...........");
  1. do referencí ve třídě Hra uložím objekty (místa) navzájem na sebe navázané
hrad.vychod = les1
  1. ve třídě hra je vytvořena další reference aktualniLokace
  2. teď následuje metoda zpracujPrikaz(), které moc nerozumím, pokud bude splněna podmínka, uloží se mi do aktualniLokace objekt, který je uložen v referenci třídy Lokace? Tedy pokud začínám v domě, bude uložen objekt les4, který je v referenci západ.
aktualniLokace = aktualniLokace.zapad

Do aktualní lokace se načte objekt, který je uložen v referenci západ? tedy (tečka)zapad je odkaz k objektu v něm uloženém a musím k tomu přistoupit přes referenci aktualniLokace, protože takto jí mám zadanou ve třídě Hra?

  1. další věcí kterou nerozumím je metoda
public Lokace vratAktualniLokaci()
    {
        return aktualniLokace;
    }

Jak funguje, co dělá? Ona má typ třídy Lokace? Tedy při vrácení aktualniLokace se vyvolá třída Lokace, tedy toString(), kde je z konstruktoru, kde se tvořily objekty míst se načtou popisy a názvy + možné směry?

Snad se to někomu bude chtít číst a ujasníte mi to. Předem děkuji.

 
Odpovědět
19.8.2020 6:49
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:19.8.2020 17:39

Předně, není to moc dobře naprogramováno.To jsi vytvořil ty nebo to je vzorové řešení? teď si to už nepamatuju.

Nahoru Odpovědět
19.8.2020 17:39
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.8.2020 17:56

Zkusím to trošku zobecnit.
Reference = odkaz na něco.

Základem všeho je proměnná. Proměnná se skládá z:

  • modifikátoru přístupu (package private, private, public či protected)
  • datového typu (objektového, primitivního)
  • názvu proměnné
  • a pak hodnoty nebo reference

Pokud máš proměnnou s primitivním datovým typem, tak tato hodnota je naplněná vždy konečnou hodnotou (nemůžeš na to už volat jiné metody a tato hodnota už je prostě konečná a nebude se nijak rozvíjet. Můžeš ji leda měnit, pracovat s ní, ale to je tak vše).

No a pak máš proměnná, která má uloženou REFERENCI (odkaz) na nějaký objekt.

Trošku názorně, abys viděl konkrétní příklady:

Máš proměnnou s priminitivním datovým typem (mimochodem, existuje pouze 8 primitivních datových typů, to jen tak pro info).

private int number = 4;

Vidíš sám, že tato proměnná má konkrétní hodnotu. Není to reference (odkaz na objekt), ale hodnota.
(Trocha filozofie.... kupříkladu JavaScript bere úplně všechno jako objekt, takže on by dokázal říct, že třeba ta čtverka je také objekt, ale v Javě, i když je Java ryze objektová, tak se toto rozlišuje).
Takže prostě a jednoduše - proměnná neodkazuje na referenci (na žádný objekt), takže už nemůžeš volat na ní žádné metody.
Nemůžeš zavolat ani třeba:

number.toString();

Naproti tomu, proměnná objektového datového typu uchovává v sobě ne hodnotu, ale REFERENCI (odkaz) na objekt.
Takže když máš třeba:

private Hrad hrad = new Hrad();

tak v proměnné hrad máš v podstatě schovaný objekt.
Proměnná objektového datového typu může dokonce už nabývat hodnoty null - to je také rozdíl třeba mezi nulou a null. Nula je konkrétní hodnota. Null znamená, že odkazuješ na žádný objekt.

A teď k tvému příkladu.

Úplně za prvé... pokud k tomu nemáš skutečně dobrý důvod a ty důvody prakticky už dneska skoro neexistují, protože se dá většinou najít čistčí řešení, tak nepiš proměnné s modifikátorem přístupu public.
Zapamatuj si konvenci, že proměnná se píše prioritně private.

Takže teď už bys mohl vědět odpověď na 1. bod
Ne, v uvedeném příkladu nevytváříš žádnou referenci.
Ono se to trošku rozděluje.

  1. deklarace proměnné
  2. inicializace/na­plnění proměnné
  3. implementace/pou­žití proměnné

To, co jsi uvedl, tak je právě deklarace. Deklarace znamená, že pouze někde uvedeš, že vytváříš proměnnou. Deklarace tedy znamená: modifikátor přístupu, datový typ a název. Nic víc

Potom je právě inicializace. To prostě ber tak,že napíšeš rovnítko a buď napíšeš konkrétní hodnotu (v případě primitivních datových typů) nebo buď vytvoříš nový objekt a nebo použiješ stávající (to v případě objektového datového typu). V případě objektového datového typu uložíš do proměnné referenci na objekt.

V bodě 2 ano, vytváříš nové objekty a uložíš je (získáš referenci na ně) do proměnných.

k dalším bodům se vyjádřím v dalším komentáři, ať to není dlouhé :)

Nahoru Odpovědět
19.8.2020 17:56
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.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:19.8.2020 18:14

u třetího bodu to říkáš špatně. Ne do referencí, ale do proměnných uložíš reference.
A pro tvoje info. Toto je čuňárna, o které jsem mluvil. Říká se tomu zapouzdření. Je nebezpečné, aby k atributům třídy měla přístup jiná třída. Toto se řeší přes tzv. přístupové metody (settery, gettery). Kdyby tě to zajímalo, mohl bych ti pak o tom víc napsat i s konkrétními příklady.

4. bod - ne není vytvořena reference. aktuálníLokace je opět proměnná, která uchovává v sobě referenci.(vždy aktuální vybranou lokaci).

5. bod. Máš tam 2 podmínky (obě rozvětvené). Pokud bude splněna první,přejde se k druhé. Pokud nebude, tak se metoda ukončí.
Možná by se sem víc hodila rekurze, než ukončovat takhle metodu a pak ji provolávat, ale to je na uvážení programátora.

V případě, že se první podmínka splní v první větvi a přejde se do další větve, tak se prochází další podmínka, která v jednotlivých případech nastaví referenci na lokaci do proměnné aktualniLokace (podle toho, jakou volbu zvolíš).

6. bod, kterému nerozumíš.
To je jedna z přístupových metod, o které jsem i mluvil. Je to tzv. getter nebo getMetoda. Anglicky se vrat řekne get :)
Tato metoda je návratová. Návratová metoda nemá void, ale datový typ, který vrátí. V podstatě je to právě ta čistá varianta, o které jsem mluvil. Neodkazuješ se přímo na proměnnou aktualniLokace, ale použiješ referenci v této proměnné přes tuto metodu.

Může se zdát, že je to zbytečné, dalo by se místo metody vratAktualniLo­kaci() používat přímo proměnnou aktualniLokace - viz příklad:

private Lokace aktualniLokace = new Lokace()

public Lokace getAktualniLokace() {
   return aktualniLokace;
}

public void metoda() {
   //A nyní můžeš napsat:
   System.out.println(getAktualniLokace());
   //A nebo:
   System.out.println(aktualniLokace);
   // Dostaneš ten samý výsledek
}

Proč to tak je přes tyto metody, tak s tím souvisí teorie a koncept OOP. Jestli bys měl zájem, můžu ti o tom teda napsat víc.

Nahoru Odpovědět
19.8.2020 18:14
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.8.2020 18:18

Víc ještě o rozdílu mezi referencí a hodnotou najdeš zde. Nenašel jsem doteď lepší článek, který by to lépe vystihl. Je skutečně nádherně zpracován a nevytkl bych tomu ani čárku mezi větou.
https://www.itnetwork.cz/…ge-collector

Nahoru Odpovědět
19.8.2020 18:18
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 5 zpráv z 5.