Proměnné, deklarace
Proměnné
-
Obecně slouží k pamatování si hodnot v paměti během chodu programu.
-
Některé — a to lokální proměnné — si pamatují jen během volání podprogramu (metody) a pak zmizí.
-
Jiné — objekty a prvky objektů — přetrvávají, jak dlouho potřebujeme, nejdéle do konce běhu programu.
-
Trvalé ukládání dat už se děje jinde — na vnějších pamětech, discích, NVRam.
Pojmenování proměnných
-
Proměnné se stejně jako pro metody a třídy pojmenovávají pomocí identifikátorů.
-
Identifikátor podobně jako např. v Pythonu musí:
-
začínat písmenem nebo znakem podtržítka
_
, které ovšem raději nepoužívejme, není to v Javě zvykem
Konvence v Javě na rozdíl od Pythonu
- názvy tříd a dalších typů, třeba výčtů, a konstant
-
začínáme písmenem velkým — třída
Person
, konstantaMAX_COUNT
- atributy, proměnné, metody…
-
malým písmenem — atribut
numHeads
, metodaprint
- víceslovné názvy
-
namísto podtržítek jako v Pythonu (
my_variable
) píšememyVariable
; kromě konstant, kde píšeme velkými písmeny a slova oddělujeme podtržítky (MAX_COUNT
)
Kategorie proměnných
V Javě jsou proměnné realizovány jako místa v paměti nesoucí hodnotu nebo odkaz na objekt. Rozlišujeme tyto kategorie podle místa výskytu proměnné:
- atributy
-
(nebo též proměnné objektu, instanční proměnné)
- statické proměnné
-
(nebo též statické atributy nebo proměnné třídy)
- lokální proměnné
-
(místní proměnné, proměnné v metodě)
Realizace proměnných
- atributy
-
uloženy v rámci dat objektu, tedy na haldě
- statické proměnné
-
uloženy v rámci dat třídy, tedy taky na haldě, ale v celém programu jen jednou
- lokální proměnné
-
na zásobníku; alokují se při volání metody (tzv. automatické proměnné)
Lokální proměnné
-
Ve příkladu s bankovními účty se v metodě
main
objevily proměnné (účty), které nebyly atributy objektů, ale pracovalo se s nimi pouze v metodě samotné. -
Takové proměnné se označují podobně jako v jiných jazycích jako lokální.
-
Podobně jako atributy mají i tyto proměnné svůj datový typ - primitivní nebo objektový.
-
V případě primitivního pak proměnná nese přímo hodnotu (například číslo nebo
boolean
). -
V případě objektového nese odkaz na objekt.
-
V tomto ohledu se to tedy nijak neliší od atributů.
Jak to přesně je?
public static void createAccount() {
Account petrsAccount = new Account();
petrsAccount.add(100.0);
}
-
petrsAccount
je lokální (automatická) proměnná metodycreateAccount
, tedy na zásobníku. -
Jedná se pouze o odkaz na objekt vytvořený při
new Account()
. -
Jakmile metoda
createAccount
skončí, zmizí hned i odkazpetrsAccount
. -
Zdali zanikne i objekt vytvořeného Account, závisí na tom, zda objekt ještě odněkud jinud "vidím", mám na něj odkaz.
-
V tomto případě již ne, takže v případě potřeby jej běhové prostředí uvolní (objekt zanikne).
Deklarace
Úplně klasicky vypadá například deklarace lokální proměnné takto:
-
Primitivní typy (čísla,
boolean
…):
int i = 2;
boolean isOK = true
-
Objektové typy:
Person jan = new Person("Honza");
// compiles iff Employee is a subclass of Person
Person petr = new Employee("Petr");
Odvození typu
-
Doposud jsme viděli, že na levé straně byl uveden deklarovaný typ proměnné.
-
V novějších verzích Javy (10+) lze využít tzn. odvození typu (type inference).
-
Z typu výrazu na pravé straně odvodíme typ proměnné na levé straně s
var
:
var petr = new Employee("Petr Servus");
// so this does not compile - Employee expected:
petr = new Person("Petr Svatý");
Odvození typového parametru
-
Kromě výše uvedených jednoduchých situací uvidíme později další.
-
U tzv. parametrizovaných typů, např. seznamů, lze odvodit typ prvku seznamu z jedné strany na druhou - i zleva doprava.
List<Person> listPeople = new ArrayList<>();
// or the type on the left is inferred to ArrayList<Person>
var listPeople = new ArrayList<Person>();
Odvození typu lambda výrazu
-
Lambda výrazy (konstrukty funkcionálního paradigmatu) jsou také typované.
-
Funguje zde odvození typů - zde se odvodí, že v seznamu jsou osoby:
var listPeople = new ArrayList<Person>();
// type of the list item is Person
// inferred type of lambda is `(Person p) -> p.print()`:
listPeople.forEach(p -> p.print());