Syntaxe Java - Java syntax

Image
Úryvek kódu Java s klíčovými slovy zvýrazněnými tučně modrým písmem

Syntax z Javy odkazuje na soubor pravidel určujících, jak je Java program psaný a interpretována.

Syntaxe je většinou odvozena z C a C ++ . Na rozdíl od C ++ v Javě neexistují žádné globální funkce nebo proměnné, ale existují datové členy, které jsou také považovány za globální proměnné . Veškerý kód patří do tříd a všechny hodnoty jsou objekty . Jedinou výjimkou jsou primitivní typy , které nejsou reprezentovány instancí třídy z důvodů výkonu (i když je lze automaticky převádět na objekty a naopak prostřednictvím autoboxingu ). Některé funkce, jako je přetížení operátoru nebo typy celých čísel bez znaménka, jsou vynechány, aby se zjednodušil jazyk a zabránilo se možným chybám při programování.

Syntaxe Java byla postupně rozšiřována v průběhu řady hlavních vydání JDK a nyní podporuje funkce, jako je generické programování a literály funkcí (v jazyce Java se nazývají výrazy lambda). Od roku 2017 vychází nová verze JDK dvakrát ročně, přičemž každé vydání přináší postupná vylepšení jazyka.

Základy

Identifikátor

Identifikátor je název prvku v kódu . Při výběru názvů prvků je třeba dodržovat určité standardní konvence pojmenování . Identifikátory v Javě rozlišují velká a malá písmena .

Identifikátor může obsahovat:

  • Libovolný znak Unicode, který je písmeno (včetně číselných písmen, jako jsou římské číslice ) nebo číslice.
  • Znak měny (například ¥).
  • Spojovací znak interpunkce (například _ ).

Identifikátor nemůže:

  • Začněte číslicí.
  • Rovná se vyhrazenému klíčovému slovu, null literálu nebo boolean literálu.

Klíčová slova

abstraktní pokračovat pro Nový přepínač
tvrdit výchozí jít do balík synchronizovány
booleovský dělat -li soukromé tento
přestávka dvojnásobek nářadí chráněný házet
byte jiný import veřejnost hází
případ enum příklad vrátit se přechodné
úlovek rozšiřuje int krátký Snaž se
char finále rozhraní statický var
třída Konečně dlouho strictfp prázdné
konst plovák rodák super nestálý
zatímco

Literály

Celá čísla
binární (zavedeno v Java SE 7) 0b11110101 ( 0b následované binárním číslem)
osmičkové 0365 ( 0 následované osmičkovým číslem)
hexadecimální 0xF5 ( 0x následované šestnáctkovým číslem)
desetinný 245 (desetinné číslo)
Hodnoty s plovoucí desetinnou čárkou
plovák 23,5F , 0,5f , 1,72E3F (desetinný zlomek s volitelným indikátorem exponent, následovaný F )
0x.5FP0F , 0x.5P-6f ( 0x následovaný hexadecimálním zlomkem s povinným indikátorem exponentu a příponou F )
dvojnásobek 23,5D , 0,5 , 1,72E3D (desetinný zlomek s volitelným indikátorem exponent, následovaný volitelným D )
0x.5FP0 , 0x.5P-6D ( 0x následovaný hexadecimálním zlomkem s indikátorem povinného exponentu a volitelnou příponou D )
Doslovné znaky
char 'a' , 'Z' , '\ u0231' (znak nebo znak únik, uzavřený v jednoduchých uvozovkách)
Booleovské literály
booleovský pravda , lež
null doslovný
nulová reference nula
Řetězcové literály
Tětiva „Hello, World“ (sekvence znaků a úniků znaků uzavřená do uvozovek)
Postavy unikají v řetězcích
Unicode znak \ u3876 ( \ u následovaný hexadecimálním bodem unicode kódu až do U+FFFF)
Osmičkový útěk \ 352 (osmičkové číslo nepřesahující 377, předchází zpětné lomítko)
Line feed \ n
Návrat vozíku \ r
Formulář \F
Obrácené lomítko \\
Jediný citát \ '
Dvojitá citace \ "
Tab \ t
Backspace \ b

Celočíselné literály jsou ve intvýchozím nastavení longtypu, pokud typ není určen připojením Lnebo lpříponou k literálu, např 367L. Od verze Java SE 7 je možné zahrnout podtržítka mezi číslice čísla, aby se zvýšila čitelnost; například číslo 145608987 lze zapsat jako 145_608_987 .

Proměnné

Proměnné jsou identifikátory spojené s hodnotami. Jsou deklarovány zapsáním typu a názvu proměnné a jsou volitelně inicializovány ve stejném příkazu přiřazením hodnoty.

int count;      //Declaring an uninitialized variable called 'count', of type 'int'
count = 35;     //Initializing the variable
int count = 35; //Declaring and initializing the variable at the same time

Více proměnných stejného typu lze deklarovat a inicializovat v jednom příkazu pomocí čárky jako oddělovače.

int a, b;         //Declaring multiple variables of the same type
int a = 2, b = 3; //Declaring and initializing multiple variables of the same type

Od verze Java 10 je možné automaticky odvozovat typy pro proměnné pomocí var.

// stream will have the FileOutputStream type as inferred from its initializer
var stream = new FileOutputStream("file.txt");

// An equivalent declaration with an explicit type
FileOutputStream stream = new FileOutputStream("file.txt");

Bloky kódu

Oddělovače { a} znamenat blok kódu a nový rozsah. Členové třídy a tělo metody jsou příklady toho, co může žít v těchto závorkách v různých kontextech.

Uvnitř těl metod lze k vytvoření nových rozsahů použít závorky, a to následovně:

void doSomething() {
    int a;

    {
        int b;
        a = 1;
    }

    a = 2;
    b = 3; // Illegal because the variable b is declared in an inner scope..
}

Komentáře

Java má tři druhy komentářů: tradiční komentáře , komentáře na konci řádku a komentáře k dokumentaci .

Tradiční komentáře, známé také jako blokové komentáře, začínají /*a končí */, mohou přesahovat na více řádků. Tento typ komentáře byl odvozen z jazyků C a C ++.

/* This is a multi-line comment.
It may occupy more than one line. */

Komentáře //na konci řádku začínají a končí až na konci aktuálního řádku. Tento typ komentáře je také v C ++ a v moderním C.

// This is an end-of-line comment

Komentáře k dokumentaci ve zdrojových souborech jsou zpracovávány nástrojem Javadoc pro generování dokumentace. Tento typ komentáře je identický s tradičními komentáři, kromě toho, že začíná /**konvencemi definovanými nástrojem Javadoc a dodržuje je. Technicky jsou tyto komentáře zvláštním druhem tradičních komentářů a nejsou specificky definovány v jazykové specifikaci.

/**
 * This is a documentation comment.
 * 
 * @author John Doe
 */

Univerzální typy

Třídy v balíčku java.lang jsou implicitně importovány do každého programu, pokud žádné explicitně importované typy nemají stejné názvy. Mezi důležité patří:

java.lang.Object
Nejlepší typ Javy . Nadtřída všech tříd, které nedeklarují nadřazenou třídu. Všechny hodnoty lze převést na tento typ, i když u primitivních hodnot to zahrnuje autobox .
java.lang.String
Základní typ řetězce Java. Neměnný . Některé metody považují každou kódovou jednotku UTF-16 za „znak“, ale jsou k dispozici také metody pro převod na int[]efektivně UTF-32 .
java.lang.Throwable
supertyp všeho, co lze házet nebo chytit pomocí Java throwa catchpříkazů.

Struktura programu

Java aplikace se skládají ze sbírek tříd. Třídy existují v balíčcích, ale mohou být také vnořeny do jiných tříd.

main metoda

Každá aplikace Java musí mít vstupní bod. To platí jak pro aplikace grafického rozhraní, tak pro aplikace konzoly. Vstupním bodem je mainmetoda. mainMetoda může mít více než jednu třídu , ale hlavní třída je vždy definována externě (například v souboru manifestu ). Metoda musí být statica je předána argumenty příkazového řádku jako pole řetězců. Na rozdíl od C ++ nebo C# nikdy nevrací hodnotu a musí se vracet void.

public static void main(String[] args) {
}

Balíčky

Balíčky jsou součástí názvu třídy a používají se ke seskupení a/nebo rozlišení pojmenovaných entit od ostatních. Dalším účelem balíčků je řídit přístup ke kódu společně s modifikátory přístupu. Například java.io.InputStreamje plně kvalifikovaný název třídy pro třídu, InputStreamkterá se nachází v balíčku java.io.

Balíček je deklarován na začátku souboru s packagedeklarací:

package myapplication.mylibrary;

public class MyClass {
}

Třídy s publicmodifikátorem musí být umístěny do souborů se stejným názvem a příponou java a vloženy do vnořených složek odpovídajících názvu balíčku. Výše uvedená třída myapplication.mylibrary.MyClassbude mít následující cestu: myapplication/mylibrary/MyClass.java.

Dovozní prohlášení

Zadejte dovozní prohlášení

Deklarace importu typu umožňuje odkazovat na pojmenovaný typ jednoduchým jménem, ​​a nikoli celým názvem, který obsahuje balíček. Importní deklarace mohou být importní deklarace jednoho typu nebo deklarace importu na vyžádání . Po deklaraci balíčku musí být importní deklarace umístěna na začátek souboru kódu.

package myPackage;

import java.util.Random; // Single type declaration

public class ImportsTest {
    public static void main(String[] args) {
        /* The following line is equivalent to
         * java.util.Random random = new java.util.Random();
         * It would've been incorrect without the import.
         */
        Random random = new Random();
    }
}

Deklarace importu na vyžádání jsou uvedeny v kódu. „Typový import“ importuje všechny typy balíčku. "Statický import" importuje členy balíčku.

import java.util.*;  /*This form of importing classes makes all classes
    in package java.util available by name, could be used instead of the
    import declaration in the previous example. */
import java.*; /*This statement is legal, but does nothing, since there
    are no classes directly in package java. All of them are in packages
    within package java. This does not import all available classes.*/

Statické dovozní prohlášení

Tento typ deklarace je k dispozici od J2SE 5.0 . Statická deklarace importu umožňuje přístup ke statickým členům definovaným v jiné třídě, rozhraní, anotaci nebo výčtu; bez zadání názvu třídy:

import static java.lang.System.out; //'out' is a static field in java.lang.System

public class HelloWorld {
    public static void main(String[] args) {
        /* The following line is equivalent to:
   System.out.println("Hi World!");

           and would have been incorrect without the import declaration. */
        out.println("Hello World!");
    }
}

Deklarace importu na vyžádání umožňují importovat všechna pole typu:

import static java.lang.System.*;
    /* This form of declaration makes all
       fields in the java.lang.System class available by name, and may be used instead
       of the import declaration in the previous example. */

Konstantní výčty lze také použít se statickým importem. Tento výčet je například v balíčku s názvem screen:

public enum ColorName {
    RED, BLUE, GREEN
};

K načtení konstant výčtu je možné použít statické deklarace importu v jiné třídě:

import screen.ColorName;
import static screen.ColorName.*;

public class Dots {
    /* The following line is equivalent to 'ColorName foo = ColorName.RED',
       and it would have been incorrect without the static import. */
    ColorName foo = RED;

    void shift() {
        /* The following line is equivalent to:

           if (foo == ColorName.RED) foo = ColorName.BLUE; */
        if (foo == RED) foo = BLUE;
    }
}

Operátoři

Operátory v Javě jsou podobné těm v C ++ . Kvůli mechanismům sběru odpadků v Javě však neexistuje žádný deleteoperátor a s ukazateli se neprovádějí žádné operace, protože je Java nepodporuje. Další rozdíl je v tom, že Java má nepodepsaný operátor pravého posunu ( ), zatímco podpis operátora pravého posunu C je závislý na typu. Operátory v Javě nelze přetížit . >>>

Přednost Operátor Popis Asociativita
1 () Vyvolání metody Zleva do prava
[] Přístup k poli
. Výběr členů třídy
2 ++ -- Přírůstek a úbytek postfixu
3 ++ -- Přírůstek a úbytek předpony Zprava doleva
+ - Unární plus a mínus
! ~ Logické NE a bitové NE
(type) val Zadejte obsazení
new Vytvoření instance třídy nebo pole
4 * / % Násobení, dělení a modul (zbytek) Zleva do prava
5 + - Sčítání a odčítání
+ Zřetězení řetězců
6 << >> >>> Bitový levý posun, podepsaný pravý posun a nepodepsaný pravý posun
7 < <= Relační „méně než“ a „méně než nebo rovno“
> >= Relační „větší než“ a „větší než nebo rovno“
instanceof Porovnání typů
8 == != Relační „rovná se“ a „není rovno“
9 & Bitové a logické AND
10 ^ Bitový a logický XOR (exkluzivní nebo)
11 | Bitové a logické NEBO (včetně nebo)
12 && Logické podmíněné-AND
13 || Logické podmíněné-NEBO
14 c ? t : f Ternární podmíněný (viz :? ) Zprava doleva
15 = Jednoduché zadání
+= -= Přiřazení součtem a rozdílem
*= /= %= Přiřazení podle produktu, podílu a zbytku
<<= >>= >>>= Přiřazení bitovým posunem doleva, podepsaným pravým posunem a nepodepsaným pravým posunem
&= ^= |= Přiřazení bitovým AND, XOR a OR

Řídicí struktury

Podmíněné výroky

if tvrzení

pokud jsou příkazy v Javě podobné těm v C a používají stejnou syntaxi:

if (i == 3) doSomething();

ifpříkaz může obsahovat volitelný elseblok, v takovém případě se stane příkazem if-then-else:

if (i == 2) {
    doSomething();
} else {
    doSomethingElse();
}

Stejně jako C, else-if konstrukce neobsahuje žádná speciální klíčová slova, je vytvořena jako sekvence samostatných příkazů if-then-else:

if (i == 3) {
    doSomething();
} else if (i == 2) {
    doSomethingElse();
} else {
    doSomethingDifferent();
}

Všimněte si také, že místo jednoduchého příkazu if lze použít například operátor ?:

int a = 1;
int b = 2;
int minVal = (a < b) ? a : b;

switch tvrzení

Switch v Javě lze použít byte, short, chara int(poznámka: ne long) primitivní datové typy, nebo jejich odpovídající typy obálky. Počínaje J2SE 5.0 je možné použít typy výčtu . Počínaje jazykem Java SE 7 je možné používat řetězce. Jiné typy odkazů nelze použít v switchpříkazech.

Možné hodnoty jsou uvedeny pomocí caseštítků. Tyto štítky v Javě mohou obsahovat pouze konstanty (včetně konstant výčtu a řetězcových konstant). Provádění začne po označení odpovídajícímu výrazu v závorkách. defaultMůže být přítomen volitelný štítek, který deklaruje, že kód následující za ním bude spuštěn, pokud žádný z označení případu neodpovídá výrazu.

Kód pro každý štítek končí breakklíčovým slovem. Je možné jej vynechat, což způsobí, že provádění přejde na další štítek, během kompilace však bude obvykle hlášeno varování.

switch (ch) {
    case 'A':
        doSomething(); // Triggered if ch == 'A'
        break;
    case 'B':
    case 'C':
        doSomethingElse(); // Triggered if ch == 'B' or ch == 'C'
        break;
    default:
        doSomethingDifferent(); // Triggered in any other case
        break;
}
switch výrazy

Od verze Java 14 je možné používat výrazy přepínačů, které používají novou syntaxi šipek:

var result = switch (ch) {
    case 'A' -> Result.GREAT;
    case 'B', 'C' -> Result.FINE;
    default -> throw new ThisIsNoGoodException();
};

Alternativně existuje možnost vyjádřit totéž s yieldpříkazem, ačkoli se doporučuje upřednostňovat syntaxi šipek, protože se tím vyhnete problému náhodného propadnutí.

var result = switch (ch) {
    case 'A':
        yield Result.GREAT;
    case 'B':
    case 'C':
        yield Result.FINE;
    default:
        throw new ThisIsNoGoodException();
};

Iterační prohlášení

Iterační příkazy jsou příkazy, které jsou opakovaně prováděny, když je daná podmínka vyhodnocena jako pravdivá. Od J2SE 5.0 má Java čtyři formy takových příkazů.

while smyčka

Ve whilesmyčce se test provádí před každou iterací.

while (i < 10) {
    doSomething();
}

do ... while smyčka

Ve do ... whilesmyčce se test provádí po každé iteraci. V důsledku toho je kód vždy spuštěn alespoň jednou.

// doSomething() is called at least once
do {
    doSomething();
} while (i < 10);

for smyčka

forsmyčky v Javě zahrnují inicializátor, podmínku a výraz čítače. Je možné zahrnout několik výrazů stejného druhu pomocí čárky jako oddělovače (kromě podmínky). Na rozdíl od C je však čárka pouze oddělovač a nikoli operátor.

for (int i = 0; i < 10; i++) {
    doSomething();
}
 
// A more complex loop using two variables
for (int i = 0, j = 9; i < 10; i++, j -= 3) {
    doSomething();
}

Stejně jako C jsou všechny tři výrazy volitelné. Následující smyčka je nekonečná:

for (;;) {
    doSomething();
}

Vylepšená forsmyčka

Vylepšené forsmyčky jsou k dispozici od J2SE 5.0 . Tento typ smyčky používá k vrácení každé položky v dané kolekci vestavěné iterátory přes pole a kolekce. Každý prvek je vrácen a dosažitelný v kontextu bloku kódu. Po spuštění bloku se vrátí další položka, dokud nezůstanou žádné položky. Na rozdíl od C# tento druh smyčky nezahrnuje speciální klíčové slovo, ale místo toho používá jiný styl zápisu.

for (int i : intArray) {
    doSomething(i);
}

Skoková prohlášení

Štítky

Štítky jsou označeny body v kódu použitém příkazy breaka continue. gotoKlíčové slovo Java nelze použít k přeskočení na konkrétní body v kódu.

start:
someMethod();

break tvrzení

Příkaz se breakvymyká nejbližší smyčce nebo switchpříkazu. Provádění pokračuje v příkazu po ukončeném příkazu, pokud existuje.

for (int i = 0; i < 10; i++) {
    while (true) {
        break;
    }
    // Will break to this point
}

Je možné se vymanit z vnější smyčky pomocí štítků:

outer:
for (int i = 0; i < 10; i++) {
    while (true) {
        break outer;
    }
}
// Will break to this point

continue tvrzení

Příkaz continuepřeruší aktuální iteraci aktuálního ovládacího příkazu a zahájí další iteraci. Následující whilesmyčka v níže uvedeném kódu čte znaky voláním getChar()a přeskakuje příkazy v těle smyčky, pokud jsou znaky mezery:

int ch;
while (ch == getChar()) {
    if (ch == ' ') {
        continue; // Skips the rest of the while-loop
    }

    // Rest of the while-loop, will not be reached if ch == ' '
    doSomething();
}

Štítky lze specifikovat v continueprohlášeních a breakprohlášeních:

outer:
for (String str : stringsArr) {
    char[] strChars = str.toCharArray();
    for (char ch : strChars) {
        if (ch == ' ') {
            /* Continues the outer cycle and the next
            string is retrieved from stringsArr */
            continue outer;
        }
        doSomething(ch);
    }
}

return tvrzení

Příkaz returnslouží k ukončení provádění metody a vrácení hodnoty. Hodnota vrácená metodou je zapsána za returnklíčové slovo. Pokud metoda vrací cokoli jiného než void, musí použít returnpříkaz k vrácení nějaké hodnoty.

void doSomething(boolean streamClosed) {
    // If streamClosed is true, execution is stopped
    if (streamClosed) {
        return;
    }
    readFromStream();
}

int calculateSum(int a, int b) {
    int result = a + b;
    return result;
}

returnpříkaz okamžitě ukončí provádění, s výjimkou jednoho případu: pokud je příkaz nalezen v trybloku a je doplněn o finally, je do finallybloku předáno řízení .

void doSomething(boolean streamClosed) {
    try {
        if (streamClosed) {
            return;
        }
        readFromStream();
    } finally {
        /* Will be called last even if 
        readFromStream() was not called */
        freeResources();
    }
}

Prohlášení o zpracování výjimek

try-catch-finally prohlášení

Výjimky jsou spravovány v rámci try... catchbloků.

try {
    // Statements that may throw exceptions
    methodThrowingExceptions();
} catch (Exception ex) {
    // Exception caught and handled here
    reportException(ex);
} finally {
    // Statements always executed after the try/catch blocks
    freeResources();
}

Provádějí se příkazy v trybloku a pokud některý z nich vyvolá výjimku, provádění bloku se přeruší a výjimku zpracuje catchblok. Může existovat více catchbloků, v takovém případě se provede první blok s proměnnou výjimky, jejíž typ odpovídá typu vyvolané výjimky.

Java SE 7 také zavedla klauzule multi-catch kromě klauzulí uni-catch. Tento typ klauzulí catch umožňuje Javě zpracovávat různé typy výjimek v jednom bloku za předpokladu, že nejsou navzájem podtřídami.

try {
    methodThrowingExceptions();
} catch (IOException | IllegalArgumentException ex) {
    //Both IOException and IllegalArgumentException will be caught and handled here
    reportException(ex);
}

Pokud se žádný catchtyp shoduje s typem vyvolané výjimky, provádění vnějšího bloku (nebo metody) obsahujícího try... catchpříkaz se přeruší a výjimka se předá nahoru a mimo obsahující blok (nebo metodu). Výjimka se šíří vzhůru prostřednictvím zásobníku volání, dokud catchse v rámci jedné z aktuálně aktivních metod nenajde odpovídající blok. Pokud se výjimka šíří až po nejlepší mainmetodu, aniž by catchbyl nalezen odpovídající blok, je do standardního výstupního proudu zapsán textový popis výjimky.

Příkazy v finallybloku jsou vždy provedeny po blocích trya catch, bez ohledu na to, zda byla vyvolána výjimka, ai když returnbylo dosaženo příkazu. Takové bloky jsou užitečné pro poskytování vyčištění kódu, který je zaručeno, že bude vždy spuštěn.

catchA finallybloky jsou volitelné, ale alespoň jeden nebo druhý musí být přítomen po trybloku.

try-prohlášení o zdrojích

tryPříkazy -with-resources jsou speciální typ try-catch-finallypříkazů zavedených jako implementace vzoru Dispose v Java SE 7. V trypříkazu -with-resources je za tryklíčovým slovem inicializace jednoho nebo více zdrojů, které se automaticky uvolní při spuštění trybloku je dokončena. Zdroje se musí implementovat java.lang.AutoCloseable. tryNa rozdíl od běžných příkazů se nevyžaduje, aby příkazy -with-resources měly a catchnebo finallyblock try-catch-finally.

try (FileOutputStream fos = new FileOutputStream("filename");
    XMLEncoder xEnc = new XMLEncoder(fos)) {
    xEnc.writeObject(object);
} catch (IOException ex) {
    Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);
}

Od Javy 9 je možné používat již deklarované proměnné:

FileOutputStream fos = new FileOutputStream("filename");
XMLEncoder xEnc = new XMLEncoder(fos);
try (fos; xEnc) {
    xEnc.writeObject(object);
} catch (IOException ex) {
    Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);
}

throw tvrzení

Příkaz throwslouží k vyvolání výjimky a ukončení provádění bloku nebo metody. Instance vyvolané výjimky je zapsána za throwpříkazem.

void methodThrowingExceptions(Object obj) {
    if (obj == null) {
        // Throws exception of NullPointerException type
        throw new NullPointerException();
    }
    // Will not be called, if object is null
    doSomethingWithObject(obj);
}

Ovládání souběžnosti vláken

Java má vestavěné nástroje pro vícevláknové programování . Pro účely synchronizace vláken je synchronizedprohlášení obsaženo v jazyce Java.

Aby byl blok kódu synchronizován, předchází mu synchronizedklíčové slovo následované objektem zámku v závorkách. Když provádějící vlákno dosáhne synchronizovaného bloku, získá zámek vzájemného vyloučení , spustí blok a poté zámek uvolní. Do tohoto bloku nesmí vstoupit žádná vlákna, dokud zámek neuvolníte. Jako zámek lze použít jakýkoli nenulový referenční typ.

/* Acquires lock on someObject. It must be of
a reference type and must be non-null */
synchronized (someObject) {
    // Synchronized statements
}

assert tvrzení

assertprohlášení jsou k dispozici od J2SE 1.4 . Tyto typy příkazů se používají k vytváření tvrzení ve zdrojovém kódu, které lze zapnout a vypnout během provádění pro konkrétní třídy nebo balíčky. K deklaraci tvrzení se použije assertklíčové slovo následované podmíněným výrazem. Pokud vyhodnotí, falsekdy je příkaz spuštěn, je vyvolána výjimka. Toto prohlášení může obsahovat dvojtečku následovanou dalším výrazem, který bude fungovat jako zpráva podrobností výjimky.

// If n equals 0, AssertionError is thrown
assert n != 0;
/* If n equals 0, AssertionError will be thrown
with the message after the colon */
assert n != 0 : "n was equal to zero";

Primitivní typy

Primitivní typy v Javě zahrnují celočíselné typy, čísla s plovoucí desetinnou čárkou, kódové jednotky UTF-16 a logický typ. V Javě neexistují žádné nepodepsané typy kromě chartypu, který se používá k reprezentaci kódových jednotek UTF-16. Nedostatek nepodepsaných typů je kompenzován zavedením nepodepsané operace pravého posunu ( >>>), která v C ++ není k dispozici. Přesto byla kritizována nedostatek kompatibility s C a C ++, který to způsobuje.

Primitivní typy
Zadejte název Wrapper třída Hodnota Rozsah Velikost Výchozí hodnota
byte java.lang.Byte celé číslo −128 až +127 8bitový (1 bajt) 0
short java.lang.Short celé číslo −32 768 až +32 767 16bitový (2bajtový) 0
int java.lang.Integer celé číslo −2,147,483,648 až +2,147,483,647 32bitový (4bajtový) 0
long java.lang.Long celé číslo −9,223,372,036,854,775,808 až
+9,223,372,036,854,775,807
64bitový (8bajtový) 0
float java.lang.Float číslo s plovoucí desetinnou čárkou ± 1,401298E − 45 až ± 3,402823E+38 32bitový (4bajtový) 0.0f
double java.lang.Double číslo s plovoucí desetinnou čárkou ± 4,94065645841246E − 324 až
± 1,79769313486232E+308
64bitový (8bajtový) 0.0
boolean java.lang.Boolean Boolean true nebo false 1bitový (1bitový) false
char java.lang.Character Jednotka kódu UTF-16 ( znak BMP
nebo část náhradního páru)
'\u0000' přes '\uFFFF' 16bitový (2bajtový) '\u0000'

charnemusí nutně odpovídat jedinému znaku. Může představovat část náhradního páru , v takovém případě je bod kódu Unicode reprezentován posloupností dvou charhodnot.

Box a unboxing

Tato jazyková funkce byla představena v J2SE 5.0 . Box je operace převodu hodnoty primitivního typu na hodnotu odpovídajícího referenčního typu, která slouží jako obal pro tento konkrétní primitivní typ. Unboxing je obrácená operace převodu hodnoty referenčního typu (dříve v rámečku) na hodnotu odpovídajícího primitivního typu. Žádná operace nevyžaduje explicitní převod.

Příklad:

int foo = 42; // Primitive type
Integer bar = foo; /* foo is boxed to bar, bar is of Integer type,
                      which serves as a wrapper for int */
int foo2 = bar; // Unboxed back to primitive type

Referenční typy

Mezi referenční typy patří typy tříd, typy rozhraní a typy polí. Při volání konstruktoru se na haldě vytvoří objekt a proměnné se přiřadí odkaz. Když se proměnná objektu dostane mimo rozsah, odkaz se přeruší a pokud nezůstanou žádné odkazy, objekt bude označen jako odpadky. Popelář je pak po nějaké době sebere a zničí.

Referenční proměnná je, nullkdyž neodkazuje na žádný objekt.

Pole

Pole v Javě se vytvářejí za běhu, stejně jako instance třídy. Délka pole je definována při vytváření a nelze ji změnit.

int[] numbers = new int[5];
numbers[0] = 2;
numbers[1] = 5;
int x = numbers[0];

Inicializátory

// Long syntax
int[] numbers = new int[] {20, 1, 42, 15, 34};
// Short syntax
int[] numbers2 = {20, 1, 42, 15, 34};

Vícerozměrná pole

V Javě jsou vícerozměrná pole reprezentována jako pole polí. Technicky jsou reprezentovány poli odkazů na jiná pole.

int[][] numbers = new int[3][3];
numbers[1][2] = 2;

int[][] numbers2 = {{2, 3, 2}, {1, 2, 6}, {2, 4, 5}};

Vzhledem k povaze vícerozměrných polí se dílčí pole mohou lišit v délce, takže vícerozměrná pole nemusí být na rozdíl od C obdélníková:

int[][] numbers = new int[2][]; //Initialization of the first dimension only

numbers[0] = new int[3];
numbers[1] = new int[2];

Třídy

Třídy jsou základy objektově orientovaného jazyka, jako je Java. Obsahují členy, kteří ukládají a manipulují s daty. Třídy jsou rozděleny na nejvyšší úroveň a vnořené . Vnořené třídy jsou třídy umístěné uvnitř jiné třídy, které mohou přistupovat k soukromým členům uzavřené třídy. Vnořené třídy zahrnují členské třídy (které lze definovat pomocí statického modifikátoru pro jednoduché vnoření nebo bez něj pro vnitřní třídy), místní třídy a anonymní třídy .

Prohlášení

Třída nejvyšší úrovně
class Foo {
    // Class members
}
Vnitřní třída
class Foo { // Top-level class
    class Bar { // Inner class
    }
}
Vnořená třída
class Foo { // Top-level class
    static class Bar { // Nested class
    }
}
Místní třída
class Foo {
    void bar() {
        class Foobar {// Local class within a method
        }
    }
}
Anonymní třída
class Foo {
    void bar() {
        new Object() {// Creation of a new anonymous class extending Object
        };
    }
}

Instance

Nestatické členy třídy definují typy proměnných a metod instance , které souvisejí s objekty vytvořenými z této třídy. K vytvoření těchto objektů musí být třída vytvořena pomocí newoperátoru a volání konstruktoru třídy.

Foo foo = new Foo();

Přístup ke členům

K členům obou instancí a statických tříd se přistupuje pomocí .(tečkového) operátoru.

Přístup k členovi
instance Ke členům instance lze přistupovat prostřednictvím názvu proměnné.

String foo = "Hello";
String bar = foo.toUpperCase();

Přístup ke členu statické třídy Ke
statickým členům se přistupuje pomocí názvu třídy nebo jiného typu. To nevyžaduje vytvoření instance třídy. Statické členy jsou deklarovány pomocí staticmodifikátoru.

public class Foo {
    public static void doSomething() {
    }
}

// Calling the static method
Foo.doSomething();

Modifikátory

Modifikátory jsou klíčová slova používaná k úpravě deklarací typů a členů typu. Nejpozoruhodnější je, že existuje podskupina obsahující modifikátory přístupu.

  • abstract - Určuje, že třída slouží pouze jako základní třída a nelze ji vytvořit.
  • static - Používá se pouze pro členské třídy, určuje, že členská třída nepatří do konkrétní instance obsahující třídy.
  • final- Třídy označené jako finalnelze rozšiřovat a nemohou mít žádné podtřídy.
  • strictfp- Určuje, že všechny operace s plovoucí desetinnou čárkou musí být prováděny v souladu s IEEE 754 a zakazuje používání zvýšené přesnosti pro ukládání mezivýsledků.
Modifikátory přístupu

Tyto modifikátory přístupu , nebo modifikátory dědičnosti nastavit přístupnost tříd, metod a ostatních členů. Členy označené jako publiclze kontaktovat odkudkoli. Pokud třída nebo její člen nemá žádné modifikátory, předpokládá se výchozí přístup.

public class Foo {
    int go() {
        return 0;
    }

    private class Bar {
    }
}

Následující tabulka ukazuje, zda má kód v rámci třídy přístup ke třídě nebo metodě v závislosti na umístění přístupové třídy a modifikátoru pro přístupovou třídu nebo člena třídy:

Modifikátor Stejná třída nebo vnořená třída Další třída uvnitř stejného balíčku Rozšířená třída v jiném balíčku V jiném balíčku není rozšířeno
private Ano Ne Ne Ne
výchozí (balíček soukromý) Ano Ano Ne Ne
protected Ano Ano Ano Ne
public Ano Ano Ano Ano
Image
Tento obrázek popisuje rozsah členů třídy v rámci tříd a balíčků.

Konstruktory a inicializátory

Konstruktér je speciální metoda volána, když je objekt inicializovat. Jeho účelem je inicializovat členy objektu. Hlavní rozdíly mezi konstruktory a běžnými metodami jsou v tom, že konstruktory jsou volány pouze tehdy, když je vytvořena instance třídy a nikdy nic nevracejí. Konstruktory jsou deklarovány jako běžné metody, ale jsou pojmenovány podle třídy a není určen žádný návratový typ:

class Foo {
    String str;

    Foo() { // Constructor with no arguments

        // Initialization
    }

    Foo(String str) { // Constructor with one argument
        this.str = str;
    }
}

Inicializátory jsou bloky kódu, které se provádějí při vytvoření třídy nebo instance třídy. Existují dva druhy inicializátorů, statické inicializátory a inicializátory instancí .

Statické inicializátory inicializují statická pole při vytvoření třídy. Jsou deklarovány pomocí staticklíčového slova:

class Foo {
    static {
        // Initialization
    }
}

Třída je vytvořena pouze jednou. Proto se statické inicializátory nevolají více než jednou. Naopak, inicializátory instance jsou automaticky volány před voláním konstruktoru pokaždé, když je vytvořena instance třídy. Na rozdíl od konstruktorů nemohou inicializátoři instance přijímat žádné argumenty a obecně nemohou vyvolat žádné zaškrtnuté výjimky (kromě několika speciálních případů). Inicializátory instance jsou deklarovány v bloku bez klíčových slov:

class Foo {
    {
        // Initialization
    }
}

Protože Java má mechanismus shromažďování odpadků, neexistují žádné destruktory . Každý objekt má však finalize()metodu volanou před uvolněním paměti, kterou lze přepsat, aby se implementovala finalizace.

Metody

Všechny příkazy v Javě musí být umístěny v rámci metod. Metody jsou podobné funkcím, kromě toho, že patří do tříd. Metoda má návratovou hodnotu, název a obvykle některé parametry inicializované, když je volána s některými argumenty. Podobně jako v C ++ mají metody vracející nic návratový typ deklarovaný jako void. Na rozdíl od C ++ metody v Javě nesmějí mít výchozí hodnoty argumentů a metody jsou místo toho obvykle přetíženy.

class Foo {
    int bar(int a, int b) {
        return (a*2) + b;
    }

    /* Overloaded method with the same name but different set of arguments */
    int bar(int a) {
        return a*2;
    }
}

Metoda se nazývá pomocí .zápisu na objektu nebo v případě statické metody také na názvu třídy.

Foo foo = new Foo();
int result = foo.bar(7, 2); // Non-static method is called on foo

int finalResult = Math.abs(result); // Static method call

throwsKlíčové slovo označuje, že metoda způsobí výjimku. Všechny zaškrtnuté výjimky musí být uvedeny v seznamu odděleném čárkami.

void openStream() throws IOException, myException { // Indicates that IOException may be thrown
}
Modifikátory
  • abstract- Abstraktní metody mohou být přítomny pouze v abstraktních třídách , takové metody nemají tělo a musí být přepsány v podtřídě, pokud nejsou abstraktní samy o sobě.
  • static- Nastaví metodu jako statickou a přístupnou bez vytvoření instance třídy. Statické metody však nemohou přistupovat k nestatickým členům ve stejné třídě.
  • final - Deklaruje, že metodu nelze v podtřídě přepsat.
  • native- Označuje, že tato metoda je implementována prostřednictvím JNI v kódu závislém na platformě. Skutečná implementace se děje mimo kód Java a takové metody nemají tělo.
  • strictfp- Deklaruje přísnou shodu s IEEE 754 při provádění operací s plovoucí desetinnou čárkou.
  • synchronized- Deklaruje, že vlákno provádějící tuto metodu musí získat monitor. U synchronizedmetod je monitor instancí třídy nebo java.lang.Classpokud je metoda statická.
  • Modifikátory přístupu - shodné s těmi, které se používají s třídami.
Varargs

Tato jazyková funkce byla představena v J2SE 5.0 . Poslední argument metody může být deklarován jako parametr proměnné arity, v takovém případě se metoda stane metodou proměnné arity (na rozdíl od metod pevné arity) nebo jednoduše metodou varargs . To umožňuje předat metodě proměnný počet hodnot deklarovaného typu jako parametry - včetně žádných parametrů. Tyto hodnoty budou k dispozici uvnitř metody jako pole.

void printReport(String header, int... numbers) { //numbers represents varargs
    System.out.println(header);
    for (int num : numbers) {
        System.out.println(num);
    }
}

// Calling varargs method
printReport("Report data", 74, 83, 25, 96);

Pole

Pole nebo proměnné třídy lze deklarovat v těle třídy pro ukládání dat.

class Foo {
    double bar;
}

Pole lze inicializovat přímo při deklaraci.

class Foo {
    double bar = 2.3;
}
Modifikátory
  • static - Učiní z pole statický prvek.
  • final - Umožňuje inicializaci pole pouze jednou v konstruktoru nebo uvnitř inicializačního bloku nebo během jeho deklarace, podle toho, co nastane dříve.
  • transient- Udává, že toto pole nebude během serializace uloženo .
  • volatile- Pokud je pole deklarováno volatile, je zajištěno, že všechna vlákna uvidí pro proměnnou konzistentní hodnotu.

Dědictví

Třídy v Javě mohou dědit pouze z jedné třídy. Třídu lze odvodit z jakékoli třídy, která není označena jako final. Dědičnost je deklarována pomocí extendsklíčového slova. Třída se může odkazovat sama pomocí thisklíčového slova a jeho přímá nadtřída pomocí superklíčového slova.

class Foo {

}

class Foobar extends Foo {

}

Pokud třída neurčí svou nadtřídu, implicitně dědí ze java.lang.Objecttřídy. Všechny třídy v Javě jsou tedy podtřídy Objecttřídy.

Pokud nadtřída nemá konstruktor bez parametrů, podtřída musí ve svých konstruktérech určit, jaký konstruktor nadtřídy použít. Například:

class Foo {
    public Foo(int n) {
        // Do something with n
    }
}

class Foobar extends Foo {
    private int number;
    // Superclass does not have constructor without parameters
    // so we have to specify what constructor of our superclass to use and how

    public Foobar(int number) {
        super(number);
        this.number = number;
    }
}
Převažující metody

Na rozdíl od C ++ jsou všechny ne- finalmetody v Javě virtuální a mohou být přepsány dědícími třídami.

class Operation {
    public int doSomething() {
        return 0;
    }
}

class NewOperation extends Operation {
    @Override
    public int doSomething() {
        return 1;
    }
}
Abstraktní třídy

Abstract Class je třída, která je neúplná, nebo mají být považována za neúplnou. Normální třídy mohou mít abstraktní metody, tj. Metody, které jsou deklarovány, ale ještě nejsou implementovány, pouze pokud jsou abstraktní třídy. Třída C má abstraktní metody, pokud platí některá z následujících:

  • C výslovně obsahuje deklaraci abstraktní metody.
  • Kterákoli ze superclassů C má abstraktní metodu a C nedeklaruje ani nedědí metodu, která ji implementuje.
  • Přímé superinterface C deklaruje nebo dědí metodu (která je tedy nutně abstraktní) a C ani nedeklaruje, ani nedědí metodu, která ji implementuje.
  • Lze vytvořit instanci podtřídy abstraktní třídy, která sama o sobě není abstraktní, což má za následek spuštění konstruktoru pro abstraktní třídu, a tedy provedení inicializátorů pole pro proměnné instance této třídy.
package org.dwwwp.test;

/**
 * @author jcrypto
 */
public class AbstractClass {
    private static final String hello;

    static {
        System.out.println(AbstractClass.class.getName() + ": static block runtime");
        hello = "hello from " + AbstractClass.class.getName();
    }

    {
        System.out.println(AbstractClass.class.getName() + ": instance block runtime");
    }

    public AbstractClass() {
        System.out.println(AbstractClass.class.getName() + ": constructor runtime");
    }

    public static void hello() {
        System.out.println(hello);
    }
}
package org.dwwwp.test;

/**
 * @author jcrypto
 */
public class CustomClass extends AbstractClass {

    static {
        System.out.println(CustomClass.class.getName() + ": static block runtime");
    }

    {
        System.out.println(CustomClass.class.getName() + ": instance block runtime");
    }

    public CustomClass() {
        System.out.println(CustomClass.class.getName() + ": constructor runtime");
    }

    public static void main(String[] args) {
        CustomClass nc = new CustomClass();
        hello();
        //AbstractClass.hello();//also valid
    }
}

Výstup:

org.dwwwp.test.AbstractClass: static block runtime
org.dwwwp.test.CustomClass: static block runtime
org.dwwwp.test.AbstractClass: instance block runtime
org.dwwwp.test.AbstractClass: constructor runtime
org.dwwwp.test.CustomClass: instance block runtime
org.dwwwp.test.CustomClass: constructor runtime
hello from org.dwwwp.test.AbstractClass

Výčty

Tato jazyková funkce byla představena v J2SE 5.0 . Technicky výčty jsou jakousi třídou obsahující ve svém těle konstanty výčtu. Každá konstanta výčtu definuje instanci typu výčet. Třídy výčtu nelze vytvořit instanci kdekoli kromě samotné třídy výčtu.

enum Season {
    WINTER, SPRING, SUMMER, AUTUMN
}

Konstanty výčtu mohou mít konstruktory, které jsou volány při načtení třídy:

public enum Season {
    WINTER("Cold"), SPRING("Warmer"), SUMMER("Hot"), AUTUMN("Cooler");

    Season(String description) {
        this.description = description;
    }

    private final String description;

    public String getDescription() {
        return description;
    }
}

Výčty mohou mít těla tříd, v takovém případě jsou považovány za anonymní třídy rozšiřující třídu výčtu:

public enum Season {
    WINTER {
        String getDescription() {return "cold";}
    },
    SPRING {
        String getDescription() {return "warmer";}
    },
    SUMMER {
        String getDescription() {return "hot";}
    },
    FALL {
        String getDescription() {return "cooler";}
    };
}

Rozhraní

Rozhraní jsou typy, které neobsahují žádná pole a obvykle definují řadu metod bez skutečné implementace. Jsou užitečné k definování smlouvy s libovolným počtem různých implementací. Každé rozhraní je implicitně abstraktní. Metody rozhraní mohou mít podmnožinu modifikátorů přístupu v závislosti na jazykové verzi strictfp, která má stejný účinek jako pro třídy, a také staticod Java SE 8.

interface ActionListener {
    int ACTION_ADD = 0;
    int ACTION_REMOVE = 1;
 
    void actionSelected(int action);
}

Implementace rozhraní

Rozhraní je implementováno třídou pomocí implementsklíčového slova. Je povoleno implementovat více než jedno rozhraní, v takovém případě jsou zapsány za implementsklíčové slovo v seznamu odděleném čárkami. Třída implementující rozhraní musí přepsat všechny své metody, jinak musí být deklarována jako abstraktní.

interface RequestListener {
    int requestReceived();
}

class ActionHandler implements ActionListener, RequestListener {
    public void actionSelected(int action) {
    }

    public int requestReceived() {
    }
}

//Calling method defined by interface
RequestListener listener = new ActionHandler(); /*ActionHandler can be
                                   represented as RequestListener...*/
listener.requestReceived(); /*...and thus is known to implement
                            requestReceived() method*/

Funkční rozhraní a výrazy lambda

Tyto funkce byly zavedeny s vydáním Java SE 8. Rozhraní se automaticky stane funkčním rozhraním, pokud definuje pouze jednu metodu. V tomto případě může být implementace reprezentována jako výraz lambda namísto implementace v nové třídě, což výrazně zjednodušuje psaní kódu ve funkčním stylu . Funkční rozhraní lze volitelně anotovat @FunctionalInterfaceanotací, která kompilátoru řekne, aby zkontroloval, zda rozhraní skutečně odpovídá definici funkčního rozhraní.

// A functional interface
@FunctionalInterface
interface Calculation {
    int calculate(int someNumber, int someOtherNumber);
}

// A method which accepts this interface as a parameter
int runCalculation(Calculation calculation) {
    return calculation.calculate(1, 2);
}

// Using a lambda to call the method
runCalculation((number, otherNumber) -> number + otherNumber);

// Equivalent code which uses an anonymous class instead
runCalculation(new Calculation() {
    @Override
    public int calculate(int someNumber, int someOtherNumber) {
        return someNumber + someOtherNumber;
    }
})

Typy parametrů Lambda nemusí být plně specifikovány a lze je odvodit z rozhraní, které implementuje. Tělo Lambdy lze zapsat bez bloku těla a returnpříkazu, pokud jde pouze o výraz. Také pro ta rozhraní, která mají v metodě pouze jeden parametr, lze vynechat kulaté závorky.

// Same call as above, but with fully specified types and a body block
runCalculation((int number, int otherNumber) -> {
    return number + otherNumber;
});

// A functional interface with a method which has only a single parameter
interface StringExtender {
    String extendString(String input);
}

// Initializing a variable of this type by using a lambda
StringExtender extender = input -> input + " Extended";

Odkazy na metody

Pokud již existuje pojmenovaná metoda kompatibilní s rozhraním, není nutné používat lambdas. Tuto metodu lze předat místo lambda pomocí odkazu na metodu. Existuje několik typů odkazů na metody:

Typ odkazu Příklad Ekvivalentní lambda
Statický Integer::sum (number, otherNumber) -> number + otherNumber
Vázaný "LongString"::substring index -> "LongString".substring(index)
bez závazků String::isEmpty string -> string.isEmpty()
Konstruktor třídy ArrayList<String>::new capacity -> new ArrayList<String>(capacity)
Pole konstruktor String[]::new size -> new String[size]

Kód, nad kterým lze volání runCalculationnahradit pomocí odkazů na metody, je následující:

runCalculation(Integer::sum);

Dědictví

Rozhraní mohou dědit z jiných rozhraní stejně jako třídy. Na rozdíl od tříd je povoleno dědění z více rozhraní. Je však možné, že několik rozhraní má pole se stejným názvem, v takovém případě se stane jediným nejednoznačným členem, ke kterému není přístup.

/* Class implementing this interface must implement methods of both
ActionListener and RequestListener */
interface EventListener extends ActionListener, RequestListener {    
}

Výchozí metody

Java SE 8 zavedla do rozhraní výchozí metody, které vývojářům umožňují přidávat nové metody do stávajících rozhraní, aniž by byla narušena kompatibilita s třídami, které již rozhraní implementují. Na rozdíl od běžných metod rozhraní mají výchozí metody tělo, které se zavolá v případě, že jej implementační třída nepřepíše.

interface StringManipulator {
    String extendString(String input);
    
    // A method which is optional to implement
    default String shortenString(String input) {
        return input.substring(1);
    }
}

// This is a valid class despite not implementing all the methods
class PartialStringManipulator implements StringManipulator {
    @Override
    public String extendString(String input) {
        return input + " Extended";
    }
}

Statické metody

Statické metody jsou další jazykovou funkcí zavedenou v Java SE 8. Chovají se úplně stejně jako ve třídách.

interface StringUtils {
    static String shortenByOneSymbol(String input) {
        return input.substring(1);
    }
}

StringUtils.shortenByOneSymbol("Test");

Soukromé metody

Ve verzi Java 9 byly přidány soukromé metody. Rozhraní může mít metodu s tělem označeným jako soukromá, v takovém případě nebude viditelná pro dědění tříd. Lze jej volat z výchozích metod pro účely opětovného použití kódu.

interface Logger {
    default void logError() {
        log(Level.ERROR);
    }

    default void logInfo() {
        log(Level.INFO);
    }

    private void log(Level level) {
        SystemLogger.log(level.id);
    }
}

Anotace

Anotace v Javě představují způsob, jak vložit metadata do kódu. Tato jazyková funkce byla představena v J2SE 5.0 .

Typy anotací

Java má sadu předdefinovaných typů anotací, ale je povoleno definovat nové. Deklarace typu anotace je speciální typ deklarace rozhraní. Jsou deklarovány stejným způsobem jako rozhraní, kromě toho, že interfaceklíčovému slovu předchází @znak. Všechny anotace jsou implicitně rozšířeny z java.lang.annotation.Annotationa nelze je rozšířit z ničeho jiného.

@interface BlockingOperations {
}

Anotace mohou mít v těle stejná prohlášení jako běžná rozhraní, navíc mohou obsahovat výčty a anotace. Hlavní rozdíl je v tom, že deklarace abstraktní metody nesmí mít žádné parametry ani vyvolávat žádné výjimky. Také mohou mít výchozí hodnotu, která je deklarována pomocí defaultklíčového slova za názvem metody:

@interface BlockingOperations {
    boolean fileSystemOperations();
    boolean networkOperations() default false;
}
Použití anotací

Anotace lze použít v jakémkoli druhu deklarace, ať už jde o balíček, třídu (včetně výčtů), rozhraní (včetně anotací), pole, metodu, parametr, konstruktor nebo lokální proměnnou. Mohou být také použity s konstantami výčtu. Anotace jsou deklarovány pomocí @znaku předcházejícího názvu typu anotace, po kterém jsou páry prvků a hodnot zapsány do závorek. Všem prvkům bez výchozí hodnoty musí být přiřazena hodnota.

@BlockingOperations(/*mandatory*/ fileSystemOperations,
/*optional*/ networkOperations = true)
void openOutputStream() { //Annotated method
}

Kromě generické formy existují ještě dvě další formy pro deklaraci anotace, což jsou zkratky. Anotace značek je krátká forma, používá se, když nejsou k prvkům přiřazeny žádné hodnoty:

@Unused // Shorthand for @Unused()
void travelToJupiter() {
}

Druhá krátká forma se nazývá anotace jednoho prvku . Používá se u typů anotací obsahujících pouze jeden prvek nebo v případě, že je přítomno více prvků, ale pouze u jednoho prvku chybí výchozí hodnota. V anotaci jednoho prvku je název prvku vynechán a místo toho je zapsána pouze hodnota:

/* Equivalent for @BlockingOperations(fileSystemOperations = true).
networkOperations has a default value and
does not have to be assigned a value */

@BlockingOperations(true)
void openOutputStream() {
}

Generika

Generika nebo parametrizované typy nebo parametrický polymorfismus je jednou z hlavních funkcí představených v J2SE 5.0 . Před zavedením generik bylo nutné explicitně deklarovat všechny typy. S generiky bylo možné pracovat podobným způsobem s různými typy bez deklarování přesných typů. Hlavním účelem generik je zajistit bezpečnost typů a detekovat chyby za běhu během kompilace. Na rozdíl od C#nejsou informace o použitých parametrech za běhu k dispozici kvůli vymazání typu .

Obecné třídy

Třídy lze parametrizovat přidáním proměnné typu do hranatých závorek ( <a >) za název třídy. Umožňuje použití této proměnné typu u členů třídy namísto skutečných typů. Může existovat více než jedna typová proměnná, v takovém případě jsou deklarovány v seznamu odděleném čárkami.

Je možné omezit proměnnou typu na podtyp nějaké konkrétní třídy nebo deklarovat rozhraní, které musí typ implementovat. V tomto případě je k proměnné typu připojeno extendsklíčové slovo, za nímž následuje název třídy nebo rozhraní. Pokud je proměnná omezena jak třídou, tak rozhraním nebo pokud existuje několik rozhraní, nejprve se zapíše název třídy a poté názvy rozhraní se & znakem použitým jako oddělovač.

/* This class has two type variables, T and V. T must be 
a subtype of ArrayList and implement Formattable interface */
public class Mapper<T extends ArrayList & Formattable, V> {
    public void add(T array, V item) {
        // array has add method because it is an ArrayList subclass
        array.add(item);
    }
}

Když je deklarována proměnná parametrizovaného typu nebo je vytvořena instance, její typ je zapsán přesně ve stejném formátu jako v záhlaví třídy, kromě toho, že skutečný typ je zapsán na místo deklarace proměnné typu.

/* Mapper is created with CustomList as T and Integer as V.
CustomList must be a subclass of ArrayList and implement Formattable */
Mapper<CustomList, Integer> mapper = new Mapper<CustomList, Integer>();

Od Java SE 7 je možné <>místo argumentů typu použít diamond ( ), v takovém případě bude odvozeno druhé. Následující kód v jazyce Java SE 7 je ekvivalentní kódu v předchozím příkladu:

Mapper<CustomList, Integer> mapper = new Mapper<>();

Při deklarování proměnné pro parametrizovaný typ je možné místo explicitních názvů typů použít zástupné znaky. Zástupné znaky jsou vyjádřeny znakem psaní ?místo skutečného typu. Je možné omezit možné typy na podtřídy nebo nadtřídy určité konkrétní třídy zapsáním extendsklíčového slova nebo superklíčového slova odpovídajícím způsobem za názvem třídy.

/* Any Mapper instance with CustomList as the first parameter
may be used regardless of the second one.*/
Mapper<CustomList, ?> mapper;
mapper = new Mapper<CustomList, Boolean>();
mapper = new Mapper<CustomList, Integer>();

/* Will not accept types that use anything but
a subclass of Number as the second parameter */
void addMapper(Mapper<?, ? extends Number> mapper) {
}

Obecné metody a konstruktory

Použití generik může být omezeno na některé konkrétní metody, tento koncept platí i pro konstruktéry. K deklarování parametrizované metody se typové proměnné zapisují před návratový typ metody ve stejném formátu jako pro obecné třídy. V případě konstruktoru jsou proměnné typu deklarovány před názvem konstruktoru.

class Mapper {
    // The class itself is not generic, the constructor is
    <T, V> Mapper(T array, V item) {
    }
}

/* This method will accept only arrays of the same type as
the searched item type or its subtype*/
static <T, V extends T> boolean contains(T item, V[] arr) {
    for (T currentItem : arr) {
        if (item.equals(currentItem)) {
            return true;
        }
    }
    return false;
}

Obecná rozhraní

Rozhraní lze parametrizovat podobným způsobem jako třídy.

interface Expandable<T extends Number> {
    void addItem(T item);
}

// This class is parameterized
class Array<T extends Number> implements Expandable<T> {
    void addItem(T item) {
    }
}

// And this is not and uses an explicit type instead
class IntegerArray implements Expandable<Integer> {
    void addItem(Integer item) {
    }
}

Viz také

Reference

externí odkazy