In aceasta lucrare de laborator vor fi acoperite urmatoarele probleme:
- Programare OO: - Generalizarea si specializarea claselor.
- Mostenirea. Rescrierea codului (overriding)
- Socket-uri: - Incapsularea adreselor IP in Java (clasa InetAddress)
- Socket-uri pentru fluxuri TCP (clasa Socket) Introducere in socket-uri -link
extern
- Socket-uri pentru servere TCP (clasa ServerSocket)
- Studiu de caz: Aplicatii client-server bazate pe socket-uri TCP
care folosesc mostenirea
- Clasele Persoana, Student,
Profesor, DatePersonale, SituatieCurs si
StudentMaster
Generalizarea
reprezinta extragerea elementelor
comune (atribute, operații și constrângeri) ale unui ansamblu de clase într-o nouă clasă mai
generală numită superclasă (care
reprezinta o abstracție a
subclaselor ei).
Rezulta o ierarhie
in care arborii de clase sunt construiți pornind de la frunze, atunci cand elementele modelului au fost
identificate, obținandu-se o descriere generica si flexibila a
soluțiilor.
Generalizarea semnifică relatia de tip "este
un" atunci cand un obiect dintr-o clasa din ansamblul generalizat este
in acelasi timp si obiect al
superclasei, si de tip "este un fel
de" atunci cand un obiect dintr-o clasa din ansamblul generalizat este
doar aproximativ si obiect al
superclasei (aproximatia venind din rescrierile codurilor operate in clasa
generalizata).
Generalizarea actioneaza in orientarea spre obiecte la doua
niveluri:
- clasele sunt generalizari
ale ansamblurilor de obiecte (un obiect este de felul definit de o clasa),
- superclasele sunt
generalizari ale unor clase (obiectele de felul specificat intr-o clasa sunt in acelasi timp si de felul specificat in superclasa).
Orientarea spre obiecte (OO) presupune ambele tipuri de
generalizare, iar limbajele
orientate spre obiecte sunt acelea care ofera ambele mecanisme de generalizare. Limbajele care ofera doar
constructii numite obiecte (si eventual clase) se pot numi limbaje care lucreaza cu obiecte (si eventual clase).
Specializarea claselor reprezinta capturarea
particularităților unui ansamblu de obiecte nediscriminate ale unei clase
existente, noile caracteristici fiind reprezentate într-o nouă clasă mai
specializată, denumită subclasă.
Specializarea usureaza
extinderea coerentă a unui ansamblu de
clase, noile cerințe fiind încapsulate în subclase care extind funcțiile
existente.
În elaborarea unei ierarhii de clase, se
cer diferite aptitudini sau competențe:
- pentru generalizare: capacitate de abstractizare, independentă de cunoștințele tehnice,
- pentru specializare: experiență si cunoștințe aprofundate într-un domeniu particular.
Moștenirea este o tehnică de generalizare oferită de limbajele de programare orientate spre obiecte pentru a construi o clasă pornind de la una sau mai multe alte clase, partajând atributele si operațiile (campurile si metodele, in Java) într-o ierarhie de clase.
In limbajul Java, orice clasa care nu
extinde in mod explicit (prin mostenire) o alta clasa Java, extinde (prin mostenire) in mod implicit
clasa Object (radacina ierarhiei de clase
Java), clasa care contine metodele necesare tuturor obiectelor create din
ierarhia de clase Java. Urmatoarele
doua declaratii de clasa sunt echivalente:
|
class NumeClasa
{ // urmeaza corpul clasei ... |
|
class
NumeClasa extends Object { // urmeaza corpul clasei ... |
Notatia UML pentru extinderea prin mostenire este o linie care uneste clasa extinsa (de baza, superclasa) de clasa care extinde (subclasa), linie terminata cu un triunghi in capatul dinspre clasa de baza. Diagrama UML corespunzatoare codului Java anterior:
Metoda toString(), metoda care are
ca scop returnarea sub forma de String a informatiilor pe care le incapsuleaza obiectul caruia i se aplica aceasta metoda.
1. In cazul claselor de biblioteca Java, metoda toString()
returneaza ansamblul valorilor curente ale atributelor obiectului.
2. In cazul claselor scrise de programator, in mod implicit metoda toString() returneaza numele clasei careia ii apartine
obiectul urmat de un cod alocat acelui obiect (hashcode).
Implementarea implicita a metodei toString() este urmatoarea:
1 2 3 4 5 6 7 |
// Implementarea implicita a metodei
toString(), // mostenita de la clasa Object public String toString()
{ // (nu returneaza continutul ci numele
clasei si codul obiectului!) return getClass().getName() +
"@" + Integer.toHexString(hashCode()); } |
3. In cazul in care programatorul doreste returnarea informatiilor
incapsulate in obiect, trebuie specificat in mod explicit un
nou cod (o noua implementare) pentru metoda toString(). Acest lucru se obtine adaugand clasei din care face parte acel obiect o
metoda cu declaratia:
|
public String toString()
{ // urmeaza corpul metodei ... |
metoda care se spune ca rescrie
(overrides) codul metodei cu acelasi nume din clasa extinsa (in acest
caz clasa Object).
Dupa adaugarea acestei metode, apelul toString() va conduce la executia noului cod, pe cand apelul super.toString() va duce la
executia codului din clasa extinsa (superclasa,
Object).
Metoda equals() are ca
scop compararea continutului
obiectului primit ca parametru cu continutul obiectului caruia i se aplica
aceasta metoda, returnand valoarea booleana true in cazul egalitatii si valoarea booleana false in cazul inegalitatii celor doua obiecte.
1. In cazul claselor de biblioteca Java, metoda equals() compara ansamblul
valorilor curente ale atributelor obiectului (continutul sau starea
obiectului). Iata, de exemplu, implementarea metodei equals() in cazul clasei String.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Implementarea explicita a metodei
equals() in clasa String public
boolean equals(Object obj)
{ // se verifica existenta unui parametru (obiect) non-null // si
faptul ca parametrul e obiect al clasei String if
((obj != null) &&
(obj instanceof String)) { String
otherString = (String)obj; //
conversie de tip int n = this.count; if (n == otherString.count) { // se compara numarul de caractere char v1[] = this.value; char v2[] = otherString.value; int i = this.offset; int j = otherString.offset; while (n-- != 0) if (v1[i++] != v2[j++]) return
false; // se compara caracterele return true; } } return false; } |
2. In cazul claselor scrise de programator, in mod implicit metoda equals() compara referinta obiectului caruia i se aplica aceasta
metoda cu referinta obiectului pasat ca parametru. Implementarea implicita a metodei equals() este urmatoarea:
1 2 3 4 5 6 |
// Implementarea implicita a metodei
equals(), // mostenita de la
clasa Object public boolean
equals(Object obj)
{ return
(this == obj); // (nu compara continutul ci
referintele!!!) } |
3. In cazul in care programatorul doreste compararea informatiilor
incapsulate in obiect, (ansamblul valorilor curente ale atributelor
obiectului) trebuie specificat in mod
explicit un nou cod (o noua implementare) pentru metoda equals(). Acest lucru se obtine adaugand clasei din care face parte acel obiect o
metoda cu declaratia:
|
public
boolean equals(Object obj)
{ // urmeaza corpul metodei ... |
metoda care rescrie (overrides) codul metodei cu acelasi nume din clasa extinsa (Object).
Dupa adaugarea acestei metode, apelul equals() va conduce
la executia noului cod, pe cand apelul super.equals()duce la executia codului din
clasa extinsa (in acest
caz codul din Object).
Java ofera, in pachetul java.net, mai multe clase pentru comunicatii in retele bazate pe IP (Internet Protocol). Clasa InetAddress incapsuleaza o adresa IP intr-un obiect care poate intoarce informatia utila. Aceasta informatie utila se obtine invocand metodele unui obiect al acestei clase. De exemplu, equals() intoarce adevarat daca doua obiecte reprezinta aceeasi adresa IP.
Clasa InetAddress nu are constructor public. De aceea, pentru a crea obiecte ale acestei clase trebuie invocata una dintre
metodele de clasa getByAddress()
si getByName().
O adresa
IP speciala este adresa IP loopback (tot ce este trimis catre
aceasta adresa IP se intoarce si devine intrare IP pentru gazda locala), cu ajutorul careia pot fi testate local
programe care utilizeaza socket-uri.
Pentru a identifica adresa IP loopback sunt folosite numele "localhost" si valoarea numerica "127.0.0.1".
Pentru a
obtine InetAddress care incapsuleaza
adresa IP loopback pot fi folosite apelurile:
|
InetAddress.getByName(null) InetAddress.getByName("localhost") InetAddress.getByName("127.0.0.1") |
Java ofera, in pachetul java.net, mai multe clase pentru lucrul cu socket-uri flux (TCP). Urmatoarele clase Java sunt implicate in
realizarea conexiunilor TCP obisnuite: ServerSocket, Socket.
Clasa ServerSocket reprezinta socket-ul
(aflat eventual pe un server bazat pe TCP) care asteapta si accepta cereri de conexiune (eventual de la un
client bazat pe TCP).
Clasa Socket reprezinta punctul terminal al unei conexiuni TCP intre
doua masini (eventual un client si un server).
Clientul (sau, mai
general, masina conector) creeaza un punct terminal Socket in momentul in care
cererea sa de conexiune este lansata si acceptata.
Serverul (sau, mai
general, masina acceptor) creeaza un Socket in momentul in care
primeste si accepta o cerere de conexiune, si
continua sa asculte si sa astepte alte cereri pe ServerSocket.
Secventa tipica a mesajelor schimbate intre client si server este urmatoarea:
Odata conexiunea stabilita, metodele getInputStream() si getOutputStream() ale clasei Socket trebuie utilizate pentru a obtine fluxuri de octeti,
de intrare respectiv iesire, pentru comunicatia intre aplicatii.
Secventa tipica pentru crearea socket-ului unei aplicatii conector (client):
1 2 3 4 5 6 7 8 |
// Stabilirea adresei
serverului String adresaServer = "localhost"; // Stabilirea portului serverului int portServer = 2000; // Crearea socketului (implicit este
realizata conexiunea cu serverul) Socket socketTCPClient = new Socket(adresaServer,
portServer); |
Dupa utilizare, socket-ul este inchis. Secventa tipica pentru inchiderea socket-ului:
1 2 |
// Inchiderea socketului (implicit a
fluxurilor TCP) socketTCPClient.close(); |
Secventa tipica pentru crearea socket-ului
server al unei aplicatii acceptor (server):
1 2 3 4 5 |
// Stabilirea portului serverului int portServer
= 2000; // Crearea socketului server (care accepta
conexiunile) ServerSocket
serverTCP = new ServerSocket(portServer);
|
Secventa tipica pentru crearea socket-ului
pentru tratarea conexiunii TCP cu un client:
1 2 3 4 |
// Blocare in asteptarea cererii de
conexiune - in momentul acceptarii // cererii se creaza socketul care
serveste conexiunea Socket conexiuneTCP = serverTCP.accept();
|
Secventa tipica pentru crearea fluxurilor de octeti asociate socket-ului (detalii fluxuri IO):
1 2 3 4 5 6 7 8 9 10 11 |
// Obtinerea fluxului de intrare octeti
TCP InputStream inTCP
= socketTCPClient.getInputStream(); // Obtinerea fluxului scanner de caractere dinspre retea Scanner scannerTCP
= new Scanner(inTCP); // Obtinerea fluxului de iesire octeti TCP OutputStream outTCP = socketTCPClient.getOutputStream(); // Obtinerea fluxului de iesire spre
retea (similar consolei de iesire) PrintStream
outRetea = new PrintStream(outTCP); |
Secventa tipica pentru trimiterea de date:
1 2 3 4 5 6 |
// Crearea unui mesaj String mesajDeTrimis = "Continut
mesaj"; // Scrierea catre retea (trimiterea
mesajului) si fortarea trimiterii outRetea.println(mesajDeTrimis); outRetea.flush(); |
Secventa tipica pentru primirea de date:
1 2 3 4 5 |
// Citirea dinspre retea (receptia unui
mesaj) String mesajPrimit = inRetea.readLine();
//
Afisarea mesajului primit
System.out.println(mesajPrimit); |
Codul unei clase care incapsuleaza tratarea conexiunilor TCP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import java.net.*; import java.io.*; import java.util.Scanner;
public class ConexiuneRetea { private Socket conexiune; private Scanner scannerTCP; private PrintStream printerTCP; public ConexiuneRetea(Socket conexiune) throws IOException { this.conexiune = conexiune; this.scannerTCP = new Scanner(conexiune.getInputStream()); this.printerTCP = new PrintStream(conexiune.getOutputStream()); } public String nextLine() { return this.scannerTCP.nextLine(); } public int nextInt() { return this.scannerTCP.nextInt(); } public void printLine(String text) { this.printerTCP.println(text); this.printerTCP.flush(); }
} |
Codul unei clase Client (pentru server cu socket TCP) care utilizeaza
ConexiuneRetea:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class Client { private ConexiuneRetea conexiune; private Socket socketTCP; private int portTCP; private InetAddress adresaIP;
public Client() throws IOException { portTCP = Integer.parseInt(JOptionPane.showInputDialog( "Client: introduceti numarul de port al serverului")); adresaIP = InetAddress.getByName(JOptionPane.showInputDialog( "Client: introduceti adresa serverului")); socketTCP = new Socket(adresaIP, portTCP); // Creare socket conexiune = new ConexiuneRetea(socketTCP); }
public static void main (String args[]) throws IOException { Client client = new Client(); String mesaj;
while(true) { mesaj = JOptionPane.showInputDialog( "Client: introduceti mesajul de trimis"); client.conexiune.printLine(mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire }
client.socketTCP.close(); // Inchiderea socketului si a fluxurilor JOptionPane.showMessageDialog(null, "Client: Bye!"); }
} |
Codul unei clase Server (bazat pe socket
TCP) care utilizeaza ConexiuneRetea:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class Server { private ConexiuneRetea conexiune; private ServerSocket serverTCP; private Socket socketTCP; private int portTCP;
public Server() throws IOException { portTCP = Integer.parseInt(JOptionPane.showInputDialog( "Server: introduceti numarul de port al serverului")); serverTCP = new ServerSocket(portTCP); // Creare socket server socketTCP = serverTCP.accept(); // Creare socket conexiune = new ConexiuneRetea(socketTCP); }
public static void main (String args[]) throws IOException { Server server = new Server(); String mesaj;
while(true) { mesaj = server.conexiune.nextLine(); JOptionPane.showMessageDialog(null, "Server: s-a primit mesajul "+mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire }
server.socketTCP.close(); // Inchiderea socketului si a fluxurilor JOptionPane.showMessageDialog(null, "Server: Bye!"); }
} |
Nu uitati: Daca bara de stare a executiei este activa () verificati cu Alt+Tab
daca a aparut o fereastra Java (in
spatele ferestrelor
vizibile). |
Observatie: Cat timp bara de stare a executiei este activa () codul nu poate fi recompilat, nu poate fi inchisa fereastra Terminal Window, etc. Pentru a opri executia, folositi right click pe si selectati Reset Machine (sau folositi direct Ctrl+Shift+Tab). |
In laborator: 1. Lansati in executie BlueJ. Inchideti proiectele anterioare (Ctrl+W). Creati un proiect socket (Project->New Project
, selectati D:/, POO2007, numarul
grupei, si scrieti socket). 2. In proiectul socket creati
clasele ConexiuneRetea,
Client
si Server
folosind codurile de mai sus. 3. Compilati codurile si creati
obiecte de tip Server. Inspectati obiectele. 4. Inspectati campurile obiectelor
(pe cele de tip ConexiuneRetea si ServerSocket). |
In laborator: 1. La unul dintre calculatoare right-click pe clasa Server.
2. Selectati si executati main(). Folositi
numarul de port 3000. 3. La un alt calculator (daca nu aveti
la dispozitie un alt calculator in retea, deschideti inca o sesiune BlueJ)
right-click
pe clasa Client,
selectati si executati main().
4. Folositi adresa primului calculator,
pe care se executa Server (adresa "localhost" in cazul in care folositi doua sesiuni
BlueJ pe acelasi calculator), si numarul de port 3000. 5. Urmariti efectul. |
Elementele comune claselor Client si Server pot forma o superclasa numita ElementeComuneClientServer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ElementeComuneClientServer { protected ConexiuneRetea conexiune; protected Socket socketTCP; protected int portTCP;
public ElementeComuneClientServer(String tip) throws IOException { portTCP = Integer.parseInt(JOptionPane.showInputDialog(tip + ": introduceti numarul de port al serverului")); } } |
Codul unei clase ClientDerivat care mosteneste si extinde clasa
ElementeComuneClientServer si ofera acelasi serviciu ca si clasa Client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ClientDerivat extends ElementeComuneClientServer { private InetAddress adresaIP;
public ClientDerivat() throws IOException { super("Client"); adresaIP = InetAddress.getByName(JOptionPane.showInputDialog( "Client: introduceti adresa serverului")); socketTCP = new Socket(adresaIP, portTCP); // Creare socket conexiune = new ConexiuneRetea(socketTCP); }
public static void main (String args[]) throws IOException { ClientDerivat client = new ClientDerivat(); String mesaj;
while(true) { mesaj = JOptionPane.showInputDialog( "Client: introduceti mesajul de trimis"); client.conexiune.printLine(mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } client.socketTCP.close(); // Inchiderea socketului si a fluxurilor JOptionPane.showMessageDialog(null, "Client: Bye!"); }
} |
Codul unei clase ServerDerivat care mosteneste si extinde clasa
ElementeComuneClientServer si ofera acelasi serviciu ca si clasa Server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ServerDerivat extends ElementeComuneClientServer { private ServerSocket serverTCP;
public ServerDerivat() throws IOException { super("Server"); serverTCP = new ServerSocket(portTCP); // Creare socket server socketTCP = serverTCP.accept(); // Creare socket conexiune = new ConexiuneRetea(socketTCP); }
public static void main (String args[]) throws IOException { ServerDerivat server = new ServerDerivat(); String mesaj;
while(true) { mesaj = server.conexiune.nextLine(); JOptionPane.showMessageDialog(null, "Server: s-a primit mesajul "+mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } server.socketTCP.close(); // Inchiderea socketului si a fluxurilor JOptionPane.showMessageDialog(null, "Server: Bye!"); }
} |
In laborator: 1. In proiectul socket creati clasele ClientDerivat,
ServerDerivat
si ElementeComuneClientServer
folosind codurile date mai sus.
2. Compilati codurile. |
Nu uitati: Daca bara de stare a executiei
este activa () verificati cu Alt+Tab daca a aparut o fereastra Java (in spatele ferestrelor
vizibile). |
Nu uitati: Pentru a opri executia, right click pe
si Reset Machine (sau Ctrl+Shift+Tab). |
In laborator: 1. La unul dintre calculatoare right-click pe clasa ServerDerivat.
2. Selectati si executati main().
Folositi numarul de port 4000. 3. La un alt calculator calculator (daca nu aveti la dispozitie un alt
calculator in retea, deschideti inca o sesiune BlueJ) right-click
pe clasa ClientDerivat,
selectati si executati main(). 4. Folositi adresa primului calculator,
pe care se executa ServerDerivat (adresa "localhost" in cazul in care folositi doua sesiuni
BlueJ pe acelasi calculator) si numarul de port 4000. 5. Urmariti efectul.
|
Sa presupunem ca dorim sa adaugam o clasa Profesor care
abstractizeaza un profesor real, prin intermediul unui camp date de tip DatePersonale, si a unui camp titlu de
tip String.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** // Campuri ascunse private DatePersonale date; private String titlu; // Constructori public Profesor(String nume, String initiale, String prenume, int
anNastere) { date
= new DatePersonale(nume, initiale, prenume, anNastere); // copiere hard } // Interfata publica
si implementarea ascunsa (include punct intrare
program) public void setTitlu(String t) {
titlu
= new String(t); // copiere hard
a obiectului primit ca parametru } public String toString() {
// forma String a campurilor return ("Profesorul " + date + " are titlul " +
titlu); } public static void main(String[] args) { // Crearea
unui nou Profesor, initializarea campurilor noului obiect Profesor pr = new Profesor("Nulescu", "Ion",
"A.", 1960); pr.setTitlu("Lector
Dr."); //
Utilizarea informatiilor privind Profesorul System.out.println(pr.toString()); // afisarea
formei String a campurilor } } |
Se observa ca avem un camp (date) comun cu clasa Student.
Putem crea o clasa Persoana care sa contina acest element comun, rescriind apoi codurile claselor Profesor si
Student pentru a extinde clasa Persoana (si
a-i refolosi campul date).
Codul noii clase Persoana va fi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** // Campuri ascunse protected DatePersonale date; // Constructori public Persoana(String nume, String initiale, String prenume, int
anNastere) { date
= new DatePersonale(nume, initiale, prenume, anNastere); // copiere hard } // Interfata publica
si implementarea ascunsa (include punct intrare
program) public String toString() { //
forma String a campurilor return (super.toString()); } public static void main(String[] args) { //
Crearea enei noi Persoane, initializarea campurilor noului obiect Persoana p = new Persoana("Julescu", "Ion",
"C.", 1965); //
Utilizarea informatiilor privind Persoana System.out.println(p.toString()); // afisarea
formei String a campurilor } } |
Vom rescrie acum codul clasei Profesor pentru a incorpora schimbarile anuntate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** // Campuri ascunse protected String titlu; // Constructori public Profesor(String nume, String initiale, String prenume, int
anNastere) { super(nume, initiale, prenume,
anNastere); // apel constructor supraclasa } // (reutilizare
cod) // Interfata publica
si implementarea ascunsa public void setTitlu(String t) {
titlu
= new String(t); // copiere hard a obiectului primit
ca parametru } public String toString() {
// forma String a campurilor return ("Profesorul " + date + " are titlul " +
titlu); } public static void main(String[] args) { //
Crearea unui nou Profesor, initializarea campurilor noului obiect Profesor pr = new Profesor("Nulescu", "Ion",
"A.", 1960); pr.setTitlu("Lector
Dr."); //
Utilizarea informatiilor privind Profesorul System.out.println(pr.toString()); // afisarea
formei String a campurilor } } |
Vom rescrie acum codul clasei Student pentru a incorpora schimbarile
anuntate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/** // Campuri ascunse protected SituatieCurs[] cursuri; protected int numarCursuri = 0; //
initializare implicita // Constructori public Student(String nume, String initiale, String prenume, int
anNastere) { super(nume, initiale, prenume,
anNastere); // apel constructor supraclasa cursuri
= new SituatieCurs[10]; //
se initializeaza doar date si cursuri } // Interfata publica
si implementarea ascunsa (include punct intrare
program) public void addCurs(String nume) { // se adauga un
nou curs cursuri[numarCursuri++]
= new SituatieCurs(nume); } public void notare(int numarCurs, int nota) { cursuri[numarCurs].notare(nota); // se adauga
nota cursului specificat } public String toString() {
// forma String a campurilor String s = "Studentul " + date + " are urmatoarele
rezultate:\n"; for (int i=0; i<numarCursuri; i++) s = s
+ cursuri[i].toString() +
"\n"; return (s); } public static void main(String[] args) { //
Crearea unui nou Student, initializarea campurilor noului obiect Student st1 = new Student("Xulescu", "Ygrec",
"Z.", 1987); st1.addCurs("CID"); st1.addCurs("MN"); st1.notare(0,
8); //
Utilizarea informatiilor privind Studentul System.out.println(st1.toString()); // afisarea
formei String a campurilor } } |
Codul clasei DatePersonale ramane nemodificat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public
class DatePersonale { // Campuri ascunse private String nume; private String initiale; private String prenume; private int anNastere; // Constructori public DatePersonale(String n, String i, String p, int an) { nume
= new String(n); // copiere hard a obiectelor primite
ca parametri, initiale
= new String(i); // adica se copiaza obiectul camp cu camp,
prenume
= new String(p); // nu doar referintele ca pana acum anNastere
= an; } // Interfata publica si implementarea ascunsa public String getNume() {
return (nume); } public String getPrenume() {
return (prenume); } public int getAnNastere() {
return (anNastere); } public String toString() { // forma String a campurilor obiectului return (nume + " " + initiale
+ " " + prenume + "
(" + anNastere +
")"); } } |
Codul clasei SituatieCurs ramane nemodificat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public
class SituatieCurs { // Campuri ascunse private int nota = 0; // initializare implicita private String denumire; // Constructor public SituatieCurs(String d) { denumire = new String(d); } // copiere hard
// se initializeaza doar denumire // Interfata publica si implementarea ascunsa public void notare(int n) { nota = n; } // se adauga
nota public int nota() {
return(nota); } // se returneaza nota public String toString() { //
forma String a campurilor if
(nota==0) return ("Disciplina
" + denumire + " nu a
fost notata"); else
return("Rezultat la disciplina " + denumire + ": " + nota); } } |
Sa presupunem ca dorim sa scriem codul unei clase noi numita StudentMaster care
sa abstractizeze un anumit subtip al tipului Student, prin adaugarea la codul clasei
Student a unui camp numit specializare de tip String.
Relatiile de utilizare (linie
punctata) si mostenire (sageti cu
triunghi in capat) in UML:
Putem scrie codul acestei clase care extinde clasa
Student astfel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/** // Campuri ascunse private String specializare; // Constructori public StudentMaster(String nume, String initiale, String
prenume, int anNastere) { super(nume, initiale, prenume,
anNastere); // apel constructor supraclasa } // Interfata publica
si implementarea ascunsa (include punct intrare
program) public void setSpecializare(String spec) { // se
stabileste specializarea specializare
= new String(spec); // copiere hard a obiectului primit } public String toString() {
// forma String a campurilor String s = "Studentul " + date + " cu specializarea "
+ specializare +
" are urmatoarele rezultate:\n"; for (int i=0; i<numarCursuri; i++) s = s
+ cursuri[i].toString() +
"\n"; return (s); } public static void main(String[] args) { //
Crearea unui nou Student, initializarea campurilor noului obiect StudentMaster sm = new StudentMaster("Rulescu",
"Ygrec", "T.", 1983); sm.addCurs("Securitate
Retele"); sm.addCurs("Servicii
Web"); sm.setSpecializare("Retele
si Software de Telecomunicatii"); sm.notare(0,
9); //
Utilizarea informatiilor privind Studentul System.out.println(sm.toString()); // afisarea
formei String a campurilor } } |
Temele vor fi predate
la lucrarea urmatoare, cate un
exemplar pentru fiecare grup de 2
studenti, sub forma de listing, continand
atat codurile sursa cat si screenshot-uri ale ecranului BlueJ
in care sa se poata vedea mesajele generate de program,
si avand numele celor doi studenti
scrise pe prima pagina sus.
Tema obligatorie:
Codurile sursa ale unor clase create
dupa modelul din sect 4.5 (Persoana, Profesor, Student, si StudentMaster) cu urmatoarea specificatie generala:
(1) Va fi creata o clasa care are elemente comune
cu clasa primita ca tema la lucrarea a 2-a (actualizata
la lucrarea a 3-a), cu numele alocat din tabelul care urmeaza,
dupa modelul clasei Profesor (@version 1.3)
- noua clasa va contine 1-2 campuri protected, un constructor public, 1-2
metode publice pentru lucrul cu campurile si o metoda publica de tip toString(),
(2) Va fi creata o clasa care contine elementele comune
ale clasei primite ca tema la lucrarea a 2a (actualizata
la lucrarea a 3-a) si a clasei nou create la punctul (1) adica le
generalizeaza, cu numele alocat din tabelul care urmeaza, dupa
modelul clasei Persoana:
- noua clasa va contine campurile comune protected, un constructor public, si o metoda publica de tip toString(),
(3) Va fi modificata clasa primita ca tema la
lucrarea a 2-a (actualizata
la lucrarea a 3-a) pentru a extinde
clasa nou creata la punctul (2) si a-i reutiliza campurile si codul
constructorului, campurile ei fiind
declarate protected
(4) Va fi modificata clasa de la punctul (1) pentru
a extinde clasa nou creata la punctul
(2) si a-i reutiliza campurile si codul constructorului, campurile ei fiind declarate protected, dupa modelul clasei Profesor (@version 1.4)
(5) Va fi creata o clasa care extinde (specializeaza)
clasa primita ca tema la lucrarea a
2-a (actualizata
la lucrarea a 3-a), cu numele alocat din tabelul care urmeaza,
dupa modelul clasei StudentMaster,
- noua clasa va contine 1-2 campuri noi private,
un constructor public, 1-2 metode publice pentru lucrul cu
campurile si o metoda publica de tip
toString(),
- metoda ei main() va afisa ceea ce returneaza metoda toString(),
Numele claselor propuse corespunzatoare numerelor de ordine
alocate la lucrarea a 2-a sunt:
|
Clasa extinsa (ca Persoana) |
Clasa initiala (ca Student) si o pereche a ei (ca Profesor) |
Clasa care extinde (ca StudentMaster) |
1 |
AparatVideo |
Monitor + Televizor |
MonitorTouchscreen + TelevizorPlat |
2 |
InstrumentEducational |
Proiector +
TablaInteractiva |
ProiectorFix + TablaInteractivaMobila |
3 |
FotoVideo |
AparatFoto +
CameraVideo |
AparatFotoMecanic
+ CameraVideoFixa |
4 |
Angajat |
Sofer +
Pilot |
SoferProfesionist
+ PilotElicopter |
5 |
TerminalPersonal |
Telefon + PDA |
TelefonDualSIM
+ PDATouchscreen |
6 |
SursaLumina |
PointerLaser
+ Lanterna |
PixCuPointerLaser
+ LanternaCuDinam |
7 |
MediuStocare |
StickUSB +
HardDiskExtern |
StickUSBCuCardSD
+ HardDiskExternAlimentatPrinUSB |
8 |
FirmaVanzari |
Magazin + MagazinOnline |
MagazinInMall
+ MagazinOnlineCuShowroom |
9 |
Autovehicul |
Autocar + Microbuz |
AutocarTurTuristic + MicrobuzHypermarket |
10 |
VehiculCuDouaRoti |
Scuter +
Motocicleta |
ScuterDeInchiriat + MotocicletaCuAtas |
11 |
ProdusMedia |
Blog + Ziar |
BlogPersonal
+ ZiarGratuit |
12 |
MediuStocare |
CDROM +
CDAudio |
CDROMDemoProdus + CDAudio |
13 |
SistemMesagerie |
Messenger +
Twitter |
YahooMessenger
+ TwitterForDisabledUsers |
14 |
DezvoltatorSoftware |
ProjectManager
+ Proiectant |
ProjectManagerDebutant
+ ProiectantFrameworkuri |
Membrii fiecarui grup vor crea fie coduri separate care sunt
utilizate de / utilizeaza clasa aleasa data trecuta, fie un cod comun care este utilizat de /
utilizeaza ambele clase ale grupului.
Teme suplimentare, pentru bonus:
I. Codurile temei obligatorii rescrise pentru a lucra cu obiecte de tip
ArrayList (ArrayList<E>)
II. Adaugarea altor metode claselor create, dandu-le astfel un caracter mai
aplicativ.
III. Adaugarea unei comunicatii client-server prin socket-uri TCP (a se vedea si lucrarea
5 si lucrarea
6) in care clasele create se
afla pe server, iar codul care le
acceseaza la client.