This is an old revision of the document!
Scopul acestui laborator este familiarizarea studenților cu noțiunile de bază ale programării în Java.
Aspectele urmărite sunt:
Aspectele bonus urmărite sunt:
În cadrul următoarelor secțiuni vă vom prezenta concepte familiare din C
, dar transpuse în limbajul Java
.
Variabilele în Java respectă formatul tradițional: tip_de_date
nume_variabilă
= valoare
. Valoarea unei variabile poate să fie un literal
(adică o valoare efectivă cum ar fi 10
, 43.9
, 'c'
etc.) sau o altă variabilă.
De asemenea, este bine să reținem diferența dintre asignare
, inițializare
și declarare
:
int x; // declarare x = 10; // asignare int y = 20; // declarare cu inițializare y = x; // de asemenea asignare
Conform POO, orice este un obiect, însă din motive de performanță, Java suportă și tipurile de bază, care nu sunt clase.
boolean isValid = true; char nameInitial = 'L'; byte hexCode = (byte)0xdeadbeef; short age = 23; int credit = -1; long userId = 169234; float percentage = 0.42f; double money = 99999;
Tip | Memorie | Interval binar | Interval de valori |
---|---|---|---|
byte | 8 biți | [-27→27-1] | [-128→127] |
short | 16 biți | [-215→215-1] | [-32768→32767] |
int | 32 biți | [-231→231-1] | [-2_147_483_648→2_147_483_647] |
long | 64 biți | [-263→263-1] | [-9_223_372_036_854_775_808→9_223_372_036_854_775_807] |
char | 16 biți | [-215→215-1] | ['\u0000'→'\uffff'] (Unicode) |
boolean | 1 bit* | [0, 1] | [false, true] |
float | 32 biți | IEEE 754: 1 bit semn, 8 biți exponent, 23 biți mantisă | [1,4e-045→3,4e+038] (precizie 7 zecimale) |
double | 64 biți | IEEE 754: 1 bit semn, 11 biți exponent, 52 biți mantisă | [4,9e-324→1,8e+308] (precizie 15 zecimale) |
Când folosim literali
cum ar fi 345
, 24.5
, 'c
', este important să știm următoarele:
345
este interpretat automat ca int24.5
este interpretat ca doubleDrept urmare avem următorul cod:
int a = 345; // valid short b = (short)20; // necesită "explicit casting" double d = 24.5; // valid float f = 35.4f; // de asemenea valid float f2 = (float)35.4; // necesită "explicit casting"
În Java, conversia între tipuri primitive se poate face implicit sau explicit, în funcție de risc și compatibilitate între tipuri.
Implicit Java convertește automat un tip mai mic într-un tip mai mare, fără pierdere de date. Se aplică tipurilor numerice byte → short → int → long → float → double
și char → int
.
byte b = 10; int i = b; // byte -> int double d = i; // int -> double, devine "10.0"
Se folosește explicit atunci când convertim un tip mai mare într-un tip mai mic, unde există risc de pierdere de date. Necesită casting manual prin (tipDestinatie)
:
double pi = 3.14; int intPi = (int) pi; // partea zecimală se pierde -> devine "3"
În Java, afișarea pe consolă se face cu obiectul standard System.out
. Acesta oferă mai multe metode, dintre care cele mai folosite sunt print()
, println()
și printf()
.
System.out.println()
System.out.print()
System.out.printf()
Metoda print()
afișează text sau valori pe consolă fără să adauge o linie nouă la final. Dacă apelăm mai multe instrucțiuni print()
, acestea vor continua pe aceeași linie.
Metoda println()
, în schimb, afișează textul și adaugă automat un caracter de sfârșit de linie \n
sau \r\n
în funcție de cum aveți setat IntelliJ-ul (LF sau CRLF pe care îl găsiți în fereastra de IntelliJ în dreapta jos).
System.out.print("Hello"); System.out.print(" World"); System.out.println("!");
Output:
Hello World!
În Java, putem combina șiruri de caractere cu variabile folosind operatorul +
. Acest lucru este mai simplu decât în C
, unde trebuia să folosim formate.
int varsta = 20; String nume = "Ana"; System.out.println("Numele este " + nume + " și are " + varsta + " ani.");
Output:
Numele este Ana și are 20 ani.
”
(ex. “Ana are mere” → șir de caractere).int
, double
, boolean
etc.) poate fi transformat automat într-un șir dacă îl concatenați cu un șir de caractere folosind operatorul +
.
Dacă vrem mai mult control asupra afișării, putem folosi printf()
, asemănător cu printf
din C
. Această metodă permite specificarea de formate:
int x = 10; double pi = Math.PI; System.out.printf("x = %d, pi = %.2f%n", x, pi);
Output:
x = 10, pi = 3.14
printf
doar dacă doriți să controlați precizia, alinierea și stilul valorilor afișate. Însă recomandarea este să folosiți print
și println
fiind mult mai lizibile.
Java folosește expresii
și declarații
pentru a descrie activitățile unui program. Expresiile produc valori, iar declarațiile execută acțiuni.
O expresie produce un rezultat (valoare) la evaluare. Valoarea poate fi numerică, de tip referință sau void (metode fără valoare de retur).
int sum = 5 + 3; // expresie numerică String s = "Hi" + " there"; // concatenare String Object o = new Object(); // expresie care returnează referință
String
și operatorul new
în laboratoarele următoare.
Operatorii combină sau alterează expresii. Precedența determină ordinea în care se evaluează operatorii, aceasta fiind fixă și reprezentată de un tabel de precedență în următoarea ordine crescătoare (de la cel mai important, la cel mai puțin important):
(
, )
++
, –
, +
, -
, !
*
, /
, %
+
, -
»
(signed right shift), «
(signed left shift), »>
(unsigned right shift), «<
(unsigned left shift)<
, >
, ⇐
, >=
==
, !=
&
, |
, ^
&&
, ||
?:
=
și asignare: +=
, -=
, /=
, *=
, %=
Reamintin că declarația definește valori (ex. int i;
), atribuirea oferă valori (ex. i = 5
) și de asemenea putem folosi atribuirea și în expresii (ex. j = (i = 5);
→ j
și i
vor avea valoarea 5
).
Structurile de control determină fluxul de execuție al unui program. În Java, cele mai comune sunt: condiționale (if
, switch
) și bucle (for
, while
, do-while
).
Permite alegerea între două sau mai multe ramuri, în funcție de o condiție booleană:
int age = 20; if (age >= 60) { System.out.println("Senior"); } else if (age >= 18) { System.out.println("Adult"); } else { System.out.println("Minor"); }
{}
sunt opționale.
Operatorul ternar este o formă scurtă de if - else
care returnează o valoare.
System.out.println(age >= 18 ? "Adult" : "Minor");
Formatul folosit de operatorul ternar este:
condiție
? expresie1
: expresie2
conditie
este true
, se evaluează și se întoarce expresie1
.conditie
este false
, se evaluează și se întoarce expresie2
.
Puteți să folosiți o expresie ternară înăuntrul unei expresii, astfel simulând un comportament de tipul if - else if - else
:
condiție if
? expresie if
: (condiție else if
? expresie else if
: expresie else
)
Mai mult, puteți simula oricâte condiții else if
folosind regula de mai sus. Acum putem transforma codul de mai sus din secțiunea if/else
astfel:
System.out.println(age >= 60 ? "Senior" : (age >= 18 ? "Adult" : "Minor"));
boolean
.if - else if - else
, nu este recomandat să facem asta pentru că reducem lizibilitatea codului. Operatorul ternar este preferat doar atunci când înlocuim structuri if - else
.
Selectează între mai multe opțiuni posibile pe baza valorii unei expresii:
int day = 3; char dayInitial; switch(day) { case 1: dayName = 'M'; break; case 2: dayName = 'T'; break; case 3: dayName = 'W'; break; case 4: dayName = 'T'; break; case 5: dayName = 'F'; break; default: dayName = 'W'; break; }
break
oprește executarea cazurilor ulterioare.default
este opțional și se execută dacă niciun case nu se potrivește.
Java 14+ permite switch expressions
pentru sintaxă mai compactă:
char size = switch(value) { case 1, 2, 3 -> 'S'; // S -> small case 4 -> 'M'; // M -> medium case 5, 6 -> 'L'; // L -> large default -> 'U'; // U -> unknown };
while
Execută blocul atât timp cât condiția este adevărată:
int count = 5; while(count > 0) { System.out.println(count); // 5 4 3 2 1 count--; } System.out.println("Done!");
do-while
Execută blocul cel puțin o dată, apoi verifică condiția:
int count = 10; do { System.out.println(count); // 10 count--; } while(count > 10);
for
Bucle de tip „counting loop”, ideale pentru iterații cunoscute:
for(int i = 0; i < 5; i++) { System.out.println(i); // 0 1 2 3 4 }
Puteți avea mai multe variabile în inițializare și incrementare:
for(int x = 0, y = 10; x < y; x++, y--) { System.out.println("(" + x + "), (" + y + ")"); // (0, 10) (1, 9) (2, 8) (3, 7) (4, 6) }
foreach
)Iterează prin colecții sau array-uri:
int[] numbers = {1, 2, 3, 4}; for(int n : numbers) { System.out.print(n + " "); // 1 2 3 4 }
break
Oprește complet bucla în care se află și continuă execuția după buclă. Dacă instrucțiunea break
se află în mai multe bucle se va opri bucla cea mai apropiată:
for (int j = 0; j < 2; j++) { for (int i = 0; i < 10; i++) { if (i == 5) break; // bucla "i" se oprește când "i" este 5 System.out.println(i); } }
continue
Sare peste restul instrucțiunilor din iterația curentă și trece la următoarea iterație a buclei:
for (int i = 0; i < 10; i++) { if (i % 2 == 0) continue; // nu se execută pentru i par System.out.println(i); // afișează doar numerele impare }
break
și continue
se folosesc doar în interiorul buclelor (for
, while
, do-while
) sau în switch (doar pentru break).
Vectorii sunt utilizați pentru a stoca mai multe valori într-o singură variabilă. Un vector este de fapt o matrice (array) unidimensională.
String[] cars = { "Volvo", "BMW", "Ford" };
int[] intArray = new int[20]; for (int i = 0; i < intArray.length; i++) { intArray[i] = i + 1; }
De asemenea, structura pentru o matrice este similară cu cea din C
:
int[][] matrix = { {1, 2, 3}, {4, 5, 6} }; System.out.println(matrix[1][2]); // 6
new
și cum se realizează alocarea memoriei în Java.
În Java, comentariile sunt fragmente de text ignorate de compilator, folosite pentru a explica codul.
/
/
și se întinde până la sfârșitul liniei:// Acesta este un comentariu pe o linie int x = 10; // putem comenta și după cod
/
*
și se termină cu */
:/* Acesta este un comentariu pe mai multe linii */ int x = 10;
JavaDoc reprezintă o specificație care explică scopul sau înțelesul elementului căruia îi este atașat. Acesta se poate atașa fie unei clase, fie unei metode. Codul pe care îl scriem nu este complet dacă nu are acest tip de documentație, deoarece, cu toate că următoarea persoană poate să își dea seama ce face o bucată de cod, aceasta nu o să aibă nicio informație legată de utilitate sau despre direcția de dezvoltare din viitor. Fără o astfel de documentație un programator nu poate lua decizii informate despre cum să interacționeze cu codul.
Atunci când scriem documentația trebuie să ținem cont de 3 aspecte. Aceasta trebuie să fie clară, completă și concisă.
Un JavaDoc trebuie să fie ușor de citit și astfel recomandăm următoarea structură:
Această structură este o sugestie care trebuie adaptată în funcție de unde este folosită.
Block tag | Descriere | Exemplu |
---|---|---|
@param NumeParametru | Ne oferă informații legate de parametrii metodelor. Dacă anumite valori nu sunt acceptate drept argument (ex. null), acestea trebuie menționate în documentație. | @param start începutul intervalului de căutare |
{@link} | Este utilizat pentru a face o legătură cu o componentă deja existentă printr-un link. Este folosit pentru a fixa o referință. | Extinde funcționalitatea {@link metodaMeaSuper(String)} pentru a fi utilizată pe date de tip Float. |
{@code} | Folosit pentru a referi părți de cod fără a fi formatată precum text HTML. | {@code HashList} reprezintă o structură de date unde datele sunt de tipul cheie-valoare. |
Exemplu de JavaDoc în cod:
/** * Returns an image that represents a solved sudoku. * This method always returns immediately, whether or not the * image exists. It is a similar implementation to {@link solveTetris} * located in the same suite of games. * * @param path an absolute path to the location of the starting image * @param name the name of the image that represents the solved sudoku */ public Image solveSudoku(String path, String name) { try { return solve(); } catch (Exception e) { return null; } }
Un aspect foarte important în momentul în care trebuie să scrieți cod în Java este legat de modul în care scrieți, mai exact de organizarea codului în interiorul unor clase cu funcționalități bine definite. Poate cel mai important motiv al respectării acestor reguli este faptul că vă va fi de ajutor în momentele în care faceți debugging sau testing pe o sursă. Primii pași pentru a avea un cod cât mai lizibil și ușor de urmărit sunt următorii:
int a, b, x, y;
deoarece la un moment dat veți uita ce rol au acestea și ce reprezintă )
public class BadStyle{ public static void main(String[]args){ int x=10;int y=20; if(x>0) System.out.println("Pozitiv");else{System.out.println("Negativ");} for(int i=0;i<y;i++){System.out.print(i+",");} System.out.println("x="+x+" y="+y); } }
În secțiunile următoare vă vom prezenta particularități ale limbajului Java și al Java Development Kit (JDK).
.java
, mai exact în interiorul claselor pe care le vom defini în aceste fișiere (mai multe detalii despre clase în laboratoarele viitoare).
Compilatorul Java este instrumentul care transformă codul sursă scris de programator (salvat în fișiere .java
) în bytecode (salvat în fișiere .class
). Acest bytecode este un format intermediar pe care Mașina Virtuală Java (JVM) îl poate executa. În cadrul JDK, compilatorul este disponibil prin utilitarul de linie de comandă javac
.
Compilatorul javac
este o aplicație scrisă chiar în limbajul Java (click me). Asta înseamnă că el poate fi rulat pe orice calculator unde există instalat JVM (Java Virtual Machine). Nu contează dacă sistemul de operare este Windows, Linux sau macOS, același program funcționează peste tot.
Când scriem cod sursă într-un fișier .java
, acesta nu este înțeles direct de calculator. Compilatorul transformă instrucțiunile Java într-un format intermediar numit bytecode
, care se salvează într-un fișier .class
.
public class Main { public static void main(String[] args) { System.out.println("Hello World"); } }
De exemplu fișierul Main.java
de mai sus va fi converit în fișierul Main.class
. Acest fișier conține bytecode, iar la execuție va fi rulat de JVM.
În Java există câteva reguli stricte legate de fișierele .java:
.java
poate conține mai multe clase.
Dacă fișierul de mai sus s-ar numi Dog.java, am primi o eroare la compilare, deoarece clasa publică dinăuntrul fișierului se cheamă “Main” (public class Main
).
A: Pentru a facilita organizarea fișierelor în proiecte Java. O să vedeți că în proiectele care sunt scrise într-un limbaj care folosește paradigma OOP există foarte multe fișiere, iar această restricție ne ajută să navigăm mai ușor proiectul.
Java folosește pachete pentru a organiza clasele, ele fiind de fapt foldere dintr-un sistem de fișiere.
package mypackage.entrypoint public class Main { public static void main(String[] args) { System.out.println("Hello World"); } }
De exemplu, pentru codul de mai sus ne dăm seama că fișierul Main.java se află la calea src/mypackage/entrypoint/Main.java
.
src
.
Pentru fișierul Main.java
care se află în folderul src
rulăm din terminal următoarea comandă:
$ cd src/ $ javac Main.java
În urma rulării vom avea un fișier Main.class
:
$ ls
Main.class Main.java
Prin înșiruirea fișierelor Java putem compila mai multe surse în același timp, rezultând mai multe fișiere .class
în cazul în care nu există erori:
$ javac Main.java Dog.java Cat.java
$ ls
Main.class Dog.class Cat.class Main.java Dog.java Cat.java
JVM este componenta care face posibilă execuția aplicațiilor Java pe orice platformă. Ea primește bytecode-ul generat de compilator prin javac
și îl rulează într-un mediu controlat, gestionând resursele, securitatea și performanța aplicației. Astfel, programatorul scrie o singură dată codul, iar JVM se ocupă de adaptarea la sistemul de operare și hardware.
După ce am compilat codul nostru în bytecode, putem porni o instanță de JVM folosind comanda java
, de unde putem încărca proiectul nostru astfel:
$ ls Main.class Main.java $ java Main Hello World!
java
acceptă doar fișiere .class
, deci comanda java Main
se traduce în java Main.class
, dar dacă încercați să rulați java Main.class
veți avea erori.java .\Main
sau java ./Main
, scrieți direct java Main
ca să nu aveți erori.
Reamintim că metoda main
permite stocarea mai multor parametrii din linia de comandă. Pentru a rula o aplicație Java cu argumente din linia de comandă folosiți următoarea structură:
$ java MyApp arg1 arg2
Acestea pot fi accesate în program prin args[0]
, args[1]
etc. din cadrul metodei main:
public class Main { // Presupunem că s-a rulat comanda "java Main Hello World" public static void main(String[] args) { if (args.length == 2) { System.out.println(args[0] + " " + args[1]); // Hello World } else { System.out.println("Wrong number of parameters!"); } } }
O aplicație Java standalone are nevoie de cel puțin o clasă care să conțină metoda main()
. Aceasta este punctul de intrare al programului și este prima metodă executată de JVM.
Metoda main are următoarea structură:
public static void main(String[] args)
public
: accesibilă de oriunde.static
: poate fi apelată fără a crea un obiect.void
: nu returnează nicio valoare.String[] args
: conține o listă de argumente primite din linia de comandă.
public
, static
și String
în următoarele laboratore. În acest lab vom scrie tot codul mereu în metoda main.
main
.
Înainte de a începe orice implementare, trebuie să vă gandiți cum grupați logica întregului program pe unități. Știm din secțiunile prezentate anterior că avem două metode de a grupa fișierele, concret prin pachete și clase.
Elementele care se regăsesc în același grup trebuie să fie conectate în mod logic, pentru o ușoară implementare și înțelegere ulterioară a codului. În cazul Java, aceste grupuri logice se plasează în pachete și se reflectă pe disc conform ierarhiei din cadrul proiectului. Reamintim că pachetele pot conține atât alte pachete, cât și fișiere sursă.
Următorul pas este delimitarea entităților din cadrul unui grup, pe baza unor trăsături individuale. În cazul nostru, aceste entități vor fi clasele care vor conține cod efectiv Java.
Pentru un exemplu de creare a unui proiect, adăugare de pachete și fișiere sursă, consultați laboratorul trecut.
Un JAR (Java ARchive) este un fișier comprimat (similar cu un .zip
) care conține clase compilate .class
, resurse (imagini, fișiere de configurare) și metadate necesare pentru rularea sau distribuirea unei aplicații Java.
După ce am compilat clasele proiectului nostru putem crea un fișier .jar
folosind comanda:
$ jar cf app.jar *.class
c
: creează un JAR nouf
: specifică numele fișierului rezultat
Un JAR poate conține un fișier special numit MANIFEST.MF (în folderul META-INF/
), unde se definește punctul de intrare al aplicației:
Main-Class: MainApp
Dacă fișierul manifest conține o definiție de tipul Main-Class
, aplicația va putea fi lansată astfel:
$ java -jar app.jar
Un sistem de build și management de proiect este responsabil cu facilitarea compilării și rulării unui proiect. Proiectele Java folosesc trei sisteme de build:
XML
.Kotlin
sau Groovy
.
Structura proiectelor cu IntelliJ build system este următoarea:
src/
:out/
: directorul unde sunt generate fișierele compilate .class
.nume-proiect.iml
: fișier cu setările modulului proiectului (dependențe, SDK folosit, output path).javac
..java
din src/
sunt compilate în .class
și puse în out/
.
În acest sistem de build se preferă linking-ul executabilelor .jar
ca dependențe. Deci este necesar să descărcați dependența voastră ca .jar
și să urmăriți pașii din acest tutorial pentru a integra dependența cu proiectul vostru.
Structura proiectelor Maven este următoarea:
src/main/java/
:org.company
în care va fi inclus codul sursă (ex. src/main/java/org/poo/Main.java
).src/main/resources/
: fișiere de configurare și resurse (ex. fișiere .properties
, XML, imagini).src/test/java/
: codul testelor unitare scrise în Java.src/test/resources/
: fișiere de configurare și resurse pentru teste.target/
: directorul unde Maven plasează fișierele rezultate în urma build-ului (fișiere .class
, .jar
, rapoarte de test).pom.xml
: fișierul central de configurare, definește dependențe, pluginuri și informații despre proiect.mvn compile
: generează fișierele .class
.mvn test
: rulează testele din src/test/java
.mvn package
: generează un executabil .jar
care conține tot codul sursă al proiectului fără teste.pom.xml
pentru a descărca dependențele necesare din repository-uri externe..java
din src/
sunt compilate în .class
și puse în target/
.
Deoarece Maven folosește formatul XML, va trebui în pom.xml să introducem label-ul <dependencies>
(care va fi închis cu un alt label </dependencies>
) în care înșiruim dependențele pe care le dorim. Dependențele pot fi luate de pe Maven Repository central unde vi se oferă și structura XML a dependenței pe care trebuie să o includeți.
De exemplu, să încercăm să adăugăm dependența Jackson de pe Maven Central care ne permite să lucrăm cu obiecte JSON la teme. Inițial pom-ul nostru arată astfel:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.company</groupId> <artifactId>nume-proiect</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>25</maven.compiler.source> <maven.compiler.target>25</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
Adăugăm după label-ul </properties>
, label-ul <dependencies>
și dăm paste la codul XML din link-ul de mai sus, după care închidem array-ul de dependențe cu </dependencies>
:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.company</groupId> <artifactId>nume-proiect</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>25</maven.compiler.source> <maven.compiler.target>25</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.20.0</version> </dependency> </dependencies> </project>
Acum avem instalat Jackson versiunea 2.20.0 în proiectul nostru. Putem verifica că proiectul este configurat corect cu noua dependență rulând din nou procesul de build cu mvn build
.
<version>
.
.idea
care este folosit de IntelliJ pentru a gestiona proiectul cu setările corecte atunci când îl deschideți. Oricând doriți să deschideți un proiect IntelliJ asigurați-vă că acel folder există.
JShell
este un instrument introdus în Java 9 care oferă un mediu interactiv (REPL – Read-Eval-Print-Loop). El permite rularea de instrucțiuni Java fără a mai crea fișiere .java
și fără a compila manual cu javac
. Este foarte util pentru testarea rapidă a expresiilor, a fragmentelor de cod sau pentru învățare.
Pentru a porni mediul interactiv scrieți în terminal jshell
:
$ jshell jshell> int x = 10; x ==> 10 jshell> x * x $1 ==> 100 jshell> System.out.println("Salut, JShell!"); Salut, JShell!
Funcționalități utile ale JShell:
/
), de exemplu:/help
: afișează ajutorul./list
: listează codul introdus./save fisier.jsh
: salvează sesiunea curentă în fisier.jsh
./exit
: termină sesiunea.Java oferă o modalitate portabilă de a configura aplicațiile prin System Properties, concret perechi cheie-valoare transmise la pornirea JVM. System properties sunt utile pentru a configura aplicația Java la momentul pornirii, fără a modifica codul sursă.
Acestea se trimit din linia de comandă folosind opțiunea -D
:
$ java -Dsurname=Popescu -Dname=Ion Main
Pentru a citi valorile în cod folosim instrucțiunea System.getProperty(“nume_proprietate”)
:
public class Main { public static void main(String[] args) { String surname = System.getProperty("surname"); String name = System.getProperty("name"); System.out.println(surname + " " + name); // Popescu Ion } }
Cazuri de utilizare frecvente:
Classpath-ul este lista de directoare și fișiere .jar
unde compilatorul javac
și JVM-ul java
caută clasele necesare pentru compilare și execuție.
Fără classpath, JVM nu știe unde să găsească clasele tale sau bibliotecile externe.
Compilarea și rularea unui proiect Java fără pachete se face astfel:
$ javac Hello.java $ java Hello
Dar în momentul în care introducem pachete, trebuie să specificăm classpath-ul. De exemplu avem fișierul Main
la calea ~/Desktop/project/src/main/java/org/example/Main.java
:
package org.example; public class Main { public static void main(String[] args){ System.out.println("Hi"); } }
Ne aflăm în directorul ~/Desktop/project/
și pentru a compila sursele folosim comanda:
$ pwd ~/Desktop/project/ $ javac src\main\java\org\example\Main.java
În urma compilării vom avea un fișier .class
la locația ~/Desktop/project/src/main/java/org/example
. Contrar așteptărilor, următoarele două comenzi nu funcționează:
$ java src.main.java.org.example.Main Error: Could not find or load main class src.main.java.org.example.Main Caused by: java.lang.NoClassDefFoundError: src/main/java/org/example/Main (wrong name: org/example/Main) $ java src/main/java/org/example/Main Error: Could not find or load main class src.main.java.org.example.Main Caused by: java.lang.NoClassDefFoundError: src/main/java/org/example/Main (wrong name: org/example/Main)
Ca să putem rula fișierul nostru trebuie să îi spunem JVM-ului unde se află pachetele noastre folosind classpath:
$ java -cp src/main/java org.example.Main Hi
Prin comanda de mai sus i-am spus JVM-ului să caute pachetele org
și example
începând cu src/main/java
.
Dacă foloseam o bibliotecă externă .jar
cum ar fi jackson.jar
care se află la calea ~/Downloads/jackson.jar
am fi referențiat-o compilatorului și JVM-ului astfel:
$ pwd ~/Desktop/project $ javac -cp ~/Downloads/jackson.jar src\main\java\org\example\Main.java $ java -cp "src/java/main:~/Downloads/jackson.jar" org.example.Main Hi
În comanda javac
de mai sus am specificat unde trebuie compilatorul să găsească biblioteca externă (~/Downloads/jackson.jar
).
În comanda java
am specificat unde trebuie JVM-ul să caute pachetele clasei main (org
și example
) și am specificat unde se află biblioteca externă (~/Downloads/jackson.jar
). Ambele căi sunt concatenate într-un singur șir de caractere, folosind :
ca separator (src/java/main
+ :
+ ~/Downloads/jackson.jar
→ src/java/main:~/Downloads/jackson.jar
).
-cp
: referențiează folderul deasupra folder-ului org
.:
pe Linux/macOS sau ;
pe Windows.
Prerequisites
javac -version
- comanda javac
este folosită pentru compilarejava -version
- comanda java
este folosită pentru rulare
Task 1 (3p)
lab1
, unde adăugați codul din secțiunea Exemplu de implementare. Rulați codul din IDE.task1
, creat în pachetul lab1
. Folosiți-vă de IDE, de exemplu Refactor → Move pentru IntelliJ. Observați ce s-a schimbat în fiecare fișier mutat.Task 2 (5p)
Creați un pachet task2
(sau alt nume pe care îl doriți să îl folosiți). În el creați clasele:
Student
cu proprietățile: name
(String), grade
(double)Internship
name
(String), minGrade
(double), students
(array de clase Student
- exemplu arrays).chooseCandidateRandomly
care returneaza in mod aleatoriu un student din lista de studenti corespunzatoare unui internship (Hint: folositi clasa Random).chooseCandidatesForInterview
care va afisa toti candidatii care au obtinut un phone interview la o anumita companie. Fiecare companie are asociat un grade minim dupa care va selecta candidatii pentru un phone interview. Astfel, daca grade-ul unui candidat este mai mare sau egal cu grade-ul minim dorit de o companie pentru angajatii sai, atunci acesta va primi un phone interview. Afisarea candidatilor se va face sub forma: “Candidate [nume_student] got a phone interview at [nume_internship]”JobMarket
cu metoda main
.Task 3 (1p)
Student
cu aceleași date în ele. Afișați rezultatul folosirii equals()
între ele. Discutați cu asistentul despre ce observați și pentru a vă explica mai multe despre această metodă.
equals
este folosită în Java pentru a compara dacă două obiecte sunt egale în ceea ce privește informațiile încapsulate în acestea. Mai precis, se compară referințele celor două obiecte. Dacă acestea indică spre aceeași zonă de memorie atunci equals
va returna true
, altfel va returna false
. Veți învăța în laboratorul 3 mai multe despre cum se folosește această funcție pentru a verifica egalitatea dintre două obiecte.
Exemplu de folosire:
if (obj1.equals(obj2)) { // do stuff }
private String name;
)