Professional Documents
Culture Documents
Pàgina 1 de 87
Curs Programació Java nivell bàsic.
Pàgina 2 de 87
Curs Programació Java nivell bàsic.
Pàgina 3 de 87
Curs Programació Java nivell bàsic.
Java és un llenguatge completament orientat a objectes. Tot en Java, excepte uns quants tipus bàsics
com són els números, són objectes i classes.
http://java.sun.com/
Trobareu gran quantitat de documentació, manuals i notícies relatives, en castellà, a www.javahispano.org
• Orientat a objectes.- L'OO en Java és comparable a C++. La major diferència entre Java i C++
és en l’herència múltiple, en la qual Java troba una solució més eficient per al compilador.
• Distribuït.- Java té una extensa llibreria d'objectes que es poden accedir amb els protocols
TCP/IP, com HTTP i FTP. Les aplicacions de Java poden obrir i accedir a objectes a través de la
xarxa mitjançant una URL (Unified Resource Locator) amb la mateixa facilitat que s'accedeix a
un sistema local de fitxers.
Pàgina 4 de 87
Curs Programació Java nivell bàsic.
• Robust.- Java pretén permetre escriure programs que han de funcionar en una gran varietat de
formes. Java posa molt èmfasi en la comprovació en temps de compilació de possibles
problemes, comprovació dinàmica (en temps d'execució) i eliminació de situacions errònies. Java
té un model de gestió de memòria que el·limina la possibilitat de sobreescriure memòria i que les
dades es corrompin.
• Interpretat.- L'interpret de Java pot executar codis binaris directament en qualsevol màquina.
Atès que l'enllaçament és un procés més incremental i lleuger, el procés de desenvolupament
pot ser molt més ràpid i exploratiu.
• Alt rendiment.- Tot i que normalment ja n'hi ha prou amb el rendiment del codi byte interpretat,
hi ha situacions en què cal més rendiment. Els codis byte poden ser traduïts a codi màquina
abans de l'execució o en temps d’execució per una aplicació que s'executi en una CPU
determinada.
• Fil múltiple (Multithread).- Els beneficis del fil múltiple dins un mateix procés són un millor
comportament en temps real i una major sensibilitat o grau de reacció. J2EE amb la tecnologia
Servlet fa un ús intensiu del fil múltiple per aconseguir un alt grau d’escalabilitat
• JFC (Java Foundation Classes). Són un conjunt de paquets de classes que estenen les
funcionalitats donades pel paquet AWT. Dins les JFC trobem, entre altres:
o Els components Swing: components gràfics que enriqueixen els components oferts per
l’API AWT (Abstract Window Toolkit) i que permeten donar un aspecte comú a totes les
aplicacions en les diferents plataformes, a diferència de les classes de l’AWT que
representen els components gràfics de manera diferent segons la plataforma. És el cas
que es dóna quan tenim una classe Java que representa una finestra. Si fem servir
l’AWT, l’aspecte serà diferent si treballem en una plataforma Windows o Macintosh
perquè s'adapta al format de finestra propi de la plataforma. En canvi, Swing
representaria gràficament la finestra de la mateixa manera a les dues plataformes.
o Java2D: permet incloure gràfics 2D d'alta qualitat, text i imatges en aplicacions Java
d'una forma més fàcil que ho fa l'AWT.
• JavaBeans. Els JavaBeans són components Java a l’estil dels components ActiveX de
Microsoft. Aquests components encapsulen funcionalitats i bàsicament serveixen per a construir
interfícies gràfiques d'una forma fàcil, mitjançant la unió de components. També es poden fer
servir per a donar funcionalitat a tasques que no corresponen només a la part client d’una
aplicació.
• RMI (Remote Method Invocation). Permet cridar mètodes a les màquines virtuals d’ordinadors
remots. És una funcionalitat, doncs, que permet cridar altres mètodes Java però no a qualsevol
mètode en qualsevol llenguatge.
Pàgina 5 de 87
Curs Programació Java nivell bàsic.
• JDBC. És una interfície homogènia d’accés a qualsevol base de dades que permeti aquest
estàndard. Com a ODBC, l’estàndard per a plataformes PC que proporciona Microsoft, indica
una interfície idèntica per a accedir a qualsevol base de dades. Tot i així, cal que a la base de
dades existeixi una part de codi que transformi les peticions en JDBC al format que compren la
base de dades concreta.
La màquina virtual de Java (Java Virtual Machine o JVM) simula una arquitectura d’ordinador simple
mitjançant el codi byte, de manera que per a qualsevol entorn es pot desenvolupar fàcilment una
màquina virtual de Java (que sí és depenent de la plataforma), i que permet executar qualsevol fitxer de
codi byte.
Però el fet de la interpretació suposa una pèrdua de rapidesa. És a dir, és més lenta la interpretació que
l'execució. Per a resoldre això es van desenvolupar dues tecnologies:
Els compiladors Just a temps són intèrprets que tradueixen el codi byte a codi nadiu just abans
d'executar per tal d’executar-lo més ràpidament.
Diverses eines per a treballar amb Java donen la facilitat de compilar el codi per tal que sigui depenent
de la plataforma i, per tant, executable (fet que trenca la portabilitat de Java). Són els anomenats
compiladors nadius.
En qualsevol cas cap de les dues tecnologies a tingut una implantació relevant en el mercat.
1.5 EL JDK
El JDK (Java Development Kit) és el producte que Sun ofereix als desenvolupadors per tal de poder
crear aplicacions en Java. El paquet inclou un conjunt d'eines que permeten compilar, depurar, generar
documentació i interpretar codi escrit en Java. S'ha creat amb el propòsit de facilitar la tasca d'aquells
que volen introduir-se en un nou llenguatge de programació que proporcioni des del principi totes les
eines necessàries per al desenvolupador.
Sun va presentar JDK com el primer producte que permetia utilitzar el llenguatge Java. Des del principi
es va crear amb el propòsit de ser una porta d'entrada al llenguatge que servís com a primera visió a
desenvolupadors i creadors d'entorns Java.
Atès que es tractava d'un entorn introductori, totes les eines funcionen en mode text sense interfície
gràfica.
La enorme evolució des de la versió 1.0 de Java ha fet que s’hagi “bifurcat” en 3 branques clarament
diferenciades:
Standard Edition: J2SE. Constitueix el “core” o nucli del que s’enten per Java. Les versions suportades
actualment per Sun són: 6, 1.5.0, 1.4.2 i 1.3.1.
Enterprise Edition: J2EE. Constitueix l’aposta tecnològica Java per desenvolupar aplicacions Web. Les
3 versions més rellevants són: J2EE 1.2.1, J2EE 1.3, J2EE 1.4 i Java EE 5. La més estesa, amb
diferència, és la J2EE 1.4
Pàgina 6 de 87
Curs Programació Java nivell bàsic.
Les últimes versions del JDK continuen donant les seves eines en mode text, és a dir, donant el mínim
necessari per a treballar en Java. Tot i així hi ha infinitat de IDE’s, de fabricats i de software lliure per
escollir. Aquí en teniu un parell de cada:
De fabricants:
Borland Jbuilder
Oracle Jdeveloper. És que es farà servir durant el curs, donat que és sobre el que sistemes –
suport d’aplicacions proveeix suport.
Lliures
NetBeans
Eclipse
La instal·lació del JDK es pot fer per separat, baixant-la de sun, o bé ja be “inclosa” amb molts IDE’s.
• java. Intèrpret de Java. Executa els codis byte produïts pel compilador, és a dir fitxers .class.
java [ options ] classname <args>
Opcions disponibles per a totes les plataformes:
-classpath path: permet especificar el directori on es van a buscar les classes necessàries per
a executar i altres classes referenciades per les classes que executem.
-Dvariable=valor: modifica el valor a una de les variables del sistema.
-jar: Permet executar tot un programa encapsulat dins d'un arxiu JAR. Amb aquesta opció només
s'utilitzaran classes que són a dins del JAR.
-version: mostra informació de la versió.
-help: mostra un missatge informatiu sobre l'ús del programa.
-verbose: mostra un missatge cada cop que es carrega un fitxer class.
Pàgina 7 de 87
Curs Programació Java nivell bàsic.
format HTML. Els comentaris que l'analitzador busca dins el codi font estan dins blocs que
comencen amb /** i acaben amb */. Existeixen un conjunt de tags que javadoc reconeix com
especials i que comencen amb @. Alguns d'ells són @author, @version, @deprecated. La utilitat
dels indicadors (tags) és que nosaltres podem especificar si volem que la informació que els
acompanya aparegui al fitxer de documentació generat. Trobareu informació sobre com escriure els
comentaris a http://java.sun.com/j2se/javadoc/writingdoccomments/
•
javadoc [ opcions ] [ package | fitxer.java ]*
• jar. Crea fitxers amb extensió .jar que contenen classes i packages (actua com un compressor).
Les opcions són:
-c <nom de fitxer>: crea un fitxer nou.
-t <nom de fitxer>: llista els continguts del fitxer.
-x<nom de fitxer>: extreu els fitxers (tots o els que es vulgui) del fitxer.
-u<nom de fitxer>: permet actualitzar el contingut del fitxer.
-f <nom de fitxer>: especifica el nom del fitxer.
-m <nom de fitxer>: inclou informació sobre el fitxer especificat.
-0: només emmagatzema, no fa compressió ZIP.
Pàgina 8 de 87
Curs Programació Java nivell bàsic.
El millor és utilitzar el manual de referència del JDK, en format HTML. Els trobareu a:
http://java.sun.com/j2se/1.5.0/docs/api/
La pàgina està dividida en tres zones o frames:
• La llista de classes, a la part inferior esquerra, que permet veure una descripció de cadascuna
de les classes del llenguatge.
• El conjunt de paquets de Java, a la part superior esquerra. Més endavant veurem que Java
organitza totes les seves classes en paquets (packages): el paquet de les classes bàsiques del
sistema és el java.lang, el paquet per l'accés a les bases de dades és el java.sql, etc.
Escollint un dels paquets a l'àrea superior esquerra fa que la part inferior esquerra llisti només les
classes que corresponen a aquell paquet.
1. Compilar i executar mitjançant les eines del JDK el següent programa Java.
/**
* Documentació del Hello World.
* No fa res. Només imprimir el famós
* text Hello World. L'hem fet servir per
* provar el compilador i l'eina JavaDoc
*/
public class HelloWorld
{
Pàgina 9 de 87
Curs Programació Java nivell bàsic.
3. Afegir-hi comentaris al mètode1 per tal que s’indiqui el que fa (imprimir el paràmetre per consola i
retornar sempre 24).
5. Ara crearem un projecte amb el Jdeveloper, que sigui el mateix HelloWord, el compilarem,
l’executarem i el documentarem.
class IgualtatStrings
{
public static void main( String[] args)
{
String cadena1, cadena2;
if (args.length != 2)
{
System.out.println("Forma d'ús:
java IgualtatStrings primera_cadena segona_cadena");
}
else //l'usuari ha posat dos arguments a l'aplicació
{
cadena1 = args[0];
cadena2 = args[1];
if (cadena1 == cadena2)
{
System.out.println("Les dues cadenes són iguals");
}
else
{
System.out.println("Les dues cadenes són diferents");
}
}
}
}
Aquesta aplicació pot comparar els dos arguments que l'usuari li posa en línia de comandes i dir si són
iguals o no. Per exemple, si l'usuari escriu el següent:
L'aplicació també diu que són diferents, quan hauria de dir que són iguals.
• buscar a la documentació del JDK com es fa la comparació d'igualtat entre variables de tipus
String
Pàgina 10 de 87
Curs Programació Java nivell bàsic.
• arreglar el codi anterior, per tal que es comporti com s'espera i comprovar-ho.
La causa que el codi de l'enunciat no funcionés correctament és que no es poden comparar dos
objectes Java amb l'operador ==. Aquest operador només compara el valor de les dues variables. En el
cas dels objectes, les variables tenen com a valor un identificador d'objecte La comparació només
donarà el valor cert si totes dues variables fan referència al mateix objecte. Encara que dues variables,
com en el nostre cas, facin referència a dos objectes idèntics, l'operador == dirà que són diferents.
Per què passa això? És impossible preparar a l'operador == perquè pugui comparar tots els objectes
que es trobarà, tant els que vénen inclosos en el JDK com els que crearà el programador. En comptes
d’això, cada objecte ha de proporcionar la seva funció de comparació. Tornarem a parlar amb més detall
d’aquest problema més endavant.
Pàgina 11 de 87
Curs Programació Java nivell bàsic.
2 Java, el llenguatge no OO
2.1 Introducció.
En aquest mòdul Començarem a programar en Java sense entrar encara en el paradigma de
l'Orientació a Objectes. L'utilitzarem com si fos un llenguatge clàssic, com C, PASCAL o PHP. És a dir,
tot i tenir una metralladora, dispararem les bales d’una en una, com si tinguéssim una pistola.
La sintaxi de Java és una simplificació de la sintaxi de C i C++.
• Paraules reservades. Paraules que s'ha predefinit en el llenguatge Java (no es poden utilitzar
com a identificadors).
2.2.1 Comentaris
Es poden afegir comentaris en Java de les dues mateixes maneres que en C++.
El primer tipus de comentari comença amb '/*', acaba amb '*/ ' i permet afegir comentaris de més d'una
línia de text. Normalment no es poden imbricar, és a dir, incloure comentaris dins de comentaris.
Exemple:
Com a cas particular, la utilitat javadoc utilitza comentaris que comencen amb '/**' i acaben amb '*/'
per tal de generar una documentació (text d'informació) del codi Java.
Exemple:
El segon tipus de comentari s'estén des de la marca '//' fins al final de la línia de text.
Exemple:
Pàgina 12 de 87
Curs Programació Java nivell bàsic.
Pàgina 13 de 87
Curs Programació Java nivell bàsic.
2.2.2 Sentències
Una sentència és una línia de codi Java. No hi ha correspondència directa entre les línies de codi i les
línies de text d'un fitxer de codi font. Java utilitza el punt i coma com a element de puntuació per indicar
el final d'una línia de codi.
Exemple: La línia
a = b + c + d + e + f + g;
a = b + c + d +
e + f + g;
Els espais entre les parts d'una sentència poden consistir en un nombre qualsevol de caràcters
separadors. S’entén per separadors, tant els caràcters d'espai en blanc com els codis de tabulació,
avanç de línia i retorn de carro.
{
i=i+1;
j= j*i;
}
Aquest bloc podria anar dins un bucle while, un if o altres sentències que tenen associat un bloc de
codi, i que veurem més endavant:
Pàgina 14 de 87
Curs Programació Java nivell bàsic.
• booleans: boolean.
• les col·leccions, objectes especials que són agrupacions dinàmiques d'altres tipus de dades
• les matrius, com a agrupació estàtica d'un tipus de dades concret (la declaració de matrius és
reconeguda directament pel compilador).
En aquest tema veurem els tipus de dades simples i les matrius, la qual cosa ens permetrà fer els
primers programes. Els objectes i les col·leccions es veuran en els propers mòduls.
byte enter amb signe de mida molt petita 8 bits Mín: -128
Màx: 127
Màx: 32767
Màx: 214748364
Màx: 9223372036854775808
Pàgina 15 de 87
Curs Programació Java nivell bàsic.
Màx:
Positiu:
3.40282347e38
Negatiu:
-1.40239846e-45
Màx:
Positiu:
1.79769313486231570e308
Negatiu:
-4.94065645841246544e-324
Pàgina 16 de 87
Curs Programació Java nivell bàsic.
2.3.3 Matrius
Una matriu o taula o array o vector és un grup de variables del mateix tipus a les quals ens podem referir
mitjançant un nom comú. El tipus de les variables pot ser primitiu (com int), o de tipus objecte (com
String).
En Java, a l'igual de llenguatges com el C, totes les taules o matrius tenen com a primera posició la
posició zero
Una matriu és realment un objecte que es gestiona per referència (és a dir, s'utilitza una direcció per tal
d'utilitzar-lo). La memòria usada per la matriu d'elements s'ha de reservar mitjançant la sentència new, ja
que declarar una variable array només crea un espai per contenir la referència a la matriu, no la memòria
que contindrà els elements de la matriu.
Als dos exemples podem veure com després de la declaració fem la reserva de memòria, que és on
realment es "crea" la matriu. Una matriu creada amb la sentència new contindrà elements inicialitzats
automàticament amb el valor predeterminat del tipus dels elements. Per tal d'inicialitzar les dades amb
un valor concret, es pot indicar de la forma següent:
int[] dies_mes =
{31 , 28 , 31 , 30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31};
Matrius multidimensionals
Pàgina 17 de 87
Curs Programació Java nivell bàsic.
Una matriu multidimensional s’implementa com una matriu de matriu. Es pot crear una matriu
multidimensional no rectangular si cada element d'una matriu es refereix a una matriu de diferents mides.
Per a inicialitzar una matriu multidimensional s'utilitzen claus imbricades:
altre_array = un_array;
solament copiarà la referència feta a aquesta array. Per copiar realment tots els valors (o part) guardats
en una matriu dins d'una altra es pot fer copiant un a un els valors de la matriu o bé utilitzant el mètode
arraycopy(origen, posició_inicial, destí, posició_inicial, longitud) de la classe
System del paquet java.lang:
System.arraycopy(un_array, 0, altre_array, 0, 3);
• les expressions
2.4.1 Identificadors
Un identificador és un nom que es dóna a una variable o objecte. Es pot escollir qualsevol nom que
comenci per una lletra i no es lletregi de la mateixa manera que una paraula reservada.
Pàgina 18 de 87
Curs Programació Java nivell bàsic.
A la sentència següent:
comptador = 325;
comptador és un identificador.
2.4.2 Literals
Sempre que un identificador sigui símbol d'un valor, un literal serà el valor concret, com 35 o "Hola".
Un tipus de dades pot tenir més d'un format possible per a un literal.
Tipus de literals:
A la sentència següent:
comptador = 325;
A la sentència següent:
nom = “Julio”;
La sentència següent:
nom = ‘Julio’;
Pàgina 19 de 87
Curs Programació Java nivell bàsic.
2.4.3 Expressions
Les expressions són combinacions de variables, paraules reservades i símbols que són avaluades com
un determinat tipus de dades. Aquest valor pot ser un nombre, una cadena o qualsevol altra classe o
tipus de dades.
Les expressions més simples són les variables aïllades o els literals. Aquestes expressions es poden
trobar al costat dret de les sentències d'assignació. Per exemple:
s = "Hola";
Com en C, una assignació té un valor en si mateixa; el valor de l’assignació és el valor de la part dreta de
la sentència:
b = a = 15;
Expressions booleanes
Les expressions booleanes són un cas especial d’expressions el valor de les quals pot ser només cert
(true) o fals (false). Les expressions booleanes no només poden aparèixer al costat dret d'una
assignació, sinó que també poden formar condicions (també anomenades expressions condicionals).
Les expressions condicionals són utilitzades a les sentències de control de flux (que veurem en aquest
mateix capítol).
Crides a funcions
Un altre tipus d'expressions són les crides a funcions. Les funcions poden ser avaluades com un tipus de
dades, per la qual cosa poden aparèixer a la part dreta de l'assignació:
a = persona.getNom();
b = persona.getCunyat(germana1);
Com que Java és un llenguatge orientat a objectes pur, les funcions sempre pertanyen a una classe.
L'estructura genèrica d'una referència a una funció o a una variable membre d'una classe és:
objecte.variable
objecte.funció(arguments);
classe.variable
classe.funció(arguments);
Pàgina 20 de 87
Curs Programació Java nivell bàsic.
Instar objectes és un tipus especial de crida a funció. Es pot utilitzar la paraula reservada new per a
cridar el constructor de la classe que s'insta:
Un exemple seria:
Avio v;
v = new Avio(747);
2.4.4 Operadors
Com hem dit, les expressions poden tenir operadors. Un operador és un símbol que transforma una
variable o la combina d'alguna manera amb una altra variable o literal.
• Operadors aritmètics
• Operadors lògics
• Operadors d'assignació
• Operador de conversió
A les pàgines següents podrem veure que alguns operadors estan sobrecarregats. És a dir, tenen més
d'un ús. Per exemple, l'operador + serveix per a sumar enters, per a sumar reals i per a concatenar
cadenes.
Però un fet a tenir en compte és que...
Autoincrement 1
++,-- Dreta
Autodecrement (major preferència)
Més Unari
+,- 2 Dreta
Menys Unari
* Multiplicació 4 Esquerra
/ Divisió 4 Esquerra
% Ròssec 4 Esquerra
Suma
+,- 5 Esquerra
Resta
A la taula anterior trobem dos camps especials: la preferència entre operadors i l'associativitat de
cada operador.
Pàgina 21 de 87
Curs Programació Java nivell bàsic.
La preferència entre operadors ens diu, dins d'una expressió, l'ordre en què s'han d'aplicar. Per exemple,
a la expressió següent:
13 + 7 * 4 - 15 / 2
el compilador, mirant les preferències entre operadors, pot adonar-se que l'ordre d'aplicació és el
següent:
13 + (7 * 4) - (15/2)
D’altra banda, l’associativitat ajuda al compilador a saber com ha d'aplicar l'operador. Per exemple, el
canvi de signe (el menys unari) ha d'anar associat al literal o variable que té a la seva dreta:
-1345
mentre que l'operador de resta va associat a l'expressió esquerra, a la qual li ha de restar el que ve a
continuació:
250 - 11
Condicional; retorna un
?: dels dos operands en 14 Dreta
funció d'un tercer
! Negació 2 Dreta
|| OR Condicional 13 Esquerra
int i;
i = i + 5;
int i;
i += 5;
Pàgina 22 de 87
Curs Programació Java nivell bàsic.
És molt important no confondre’s entre l'operador d'assignació (=) i l'operador d'igualtat (==). El següent
fragment de codi:
a = b
és una sentència on es fa una assignació del valor de b a la variable a, mentre que el fragment de codi:
a == b
és una expressió booleana que compara el valor de a i el de b, i que per si mateixa no forma cap
sentència.
Per a realitzar la conversió, s’escriu el nom del tipus a què es vol convertir entre parèntesi.
Exemple:
int i;
long l;
{
sentència_1;
sentència_2;
sentència_3;
sentència_4;
sentència_5;
sentència_6;
sentència_7;
sentència_8;
sentència_9;
sentència_10;
}
Les sentències de control de flux alteren el flux normal d'execució d'un bloc de codi per a permetre fer
algorismes més complexos. Aquestes sentències les dividirem en:
• Sentències condicionals
Pàgina 23 de 87
Curs Programació Java nivell bàsic.
• Sentències de bucle
Sentències if
if (<expressió_condicional>)
<sentència_if>
else
<sentència_else>
Per exemple:
...
if (valor==1)
{
segon_valor = 1;
}
else
{
segon_valor = 2;
}
A més, l'operador ternari ?: pot usar-se a vegades com a alternativa de les sentències if-else.
int a;
int i=0;
...
a=(i==1)?1:2;
...
Sentències switch
switch (<expressió>) {
case <valor1>:
<segment_codi_1>
case <valor2>:
<segment_codi_2>
...
case <valorN>:
<segment_codi_N>
default:
<segment_codi_per_defecte>
}
Per exemple:
switch (valor) {
case 1: valor_segon = 1;break;
Pàgina 24 de 87
Curs Programació Java nivell bàsic.
Cal incloure la sentència break al final de cada segment de codi en cada cas per tal que finalitzi
l'execució de la sentència switch quan acabi el cas corresponent.
Sentències for
for (<sentència_inicialització>;
<expressió_condicional>;
<sentència_increment>)
<cos_bucle>
Per exemple:
for (i=1;i<final;i++)
{
total = total + total*i;
}
O la forma habitual de recórrer una matriu
for (i=1;i<final;i++)
{
total = total + total*i;
}
A partir de la versió 1.5 de la J2EE ha aparegut el bucle for-each o for “millorat” que permet recorrer una matriu de la
següent forma
for (o:<vector> )
{
tractar (o);
}
Per exemple:
Sentències while
while (<expressió_condicional>)
<cos_bucle>
Pàgina 25 de 87
Curs Programació Java nivell bàsic.
Per exemple:
while (i<final)
{
i= i+1;
}
Sentències do-while
do
<cos_bucle>
while (<expressió_condicional>)
Per exemple:
do
{
i= i+1;
}while (i<final)
Sentències break
break [<etiqueta>];
etiqueta és opcional i indica on s'ha de transferir el control que es transferirà a la sentència posterior a
l'etiquetada. En el cas que no hi hagi etiqueta, la següent sentència que s'executarà serà la següent
després del bloc de codi on hi ha el break. Habitualment es fa servir (sense etiqueta) amb sentències switch.
Sentències continue
continue [<etiqueta>];
etiqueta és opcional i actua de la mateixa manera que en la sentència break.
Sentències return
return <expressió>;
i s'utilitzen per tornar el control al lloc des d'on es va fer la crida al mètode o constructor. Si es defineix un
mètode perquè retorni un valor, l'expressió ha de ser avaluada en el tipus que torni aquest mètode.
Pàgina 26 de 87
Curs Programació Java nivell bàsic.
Els fitxers de codi font en Java poden contenir solament tres tipus de sentències fora de blocs de codi:
• Sentències class: serveixen per a definir classes. Dos classes NO poden tenir mai el mateix nom, a
no ser que es trobin en packages diferents.
• Sentència package: defineix el paquet al qual pertanyen les classes del fitxer. Habitualment i,
entre d’altres motius per superar la limitació anterior respecte al nom de les classes, els packgages fan
servir una notació tipus “domini” d’internet. Podem, per exemple, tenir el package
ub.ges.grad.assignatura que permetria definir les classes relatives a assignatures, diferenciades
per exemple de les que es trobessin en el package ub.ges.giga.assignatura.
• Sentència import: estableix un mètode per referir-se a classes que ja han estat creades (com
les de l'API) únicament amb el nom de classe, sense especificar el nombre complet del paquet.
Tant les sentències de tipus package com les d'import són opcionals: només s'han de posar en cas de
necessitar-les.
Exemple:
package ub.ges.curs.llistes;
import ub.ges.curs.figures.*;
import ug.ges.curs.util.pantalles;
class NovaClasse
{
...
}
En el primer import, importem totes les classes del paquet ub.ges.curs.figures mentre que en el
segon importem la classe concreta pantalles.
Les declaracions de les variables són com qualsevol altra declaració de variables però poden tenir
modificadors que alterin la visibilitat fora de la classe:
La manera de fer la declaració de les funcions o mètodes d'una classe la veurem a continuació.
Pàgina 27 de 87
Curs Programació Java nivell bàsic.
modificador(s) especificador_tipus
identificador (arguments)
{
bloc_de_codi
}
L'especificador de tipus de dades que retorna la funció pot ser qualsevol tipus de dades o void. La
paraula reservada void, significa "cap tipus de dades", i s'utilitza per indicar que un mètode no retorna
cap valor.
L'identificador del mètode és el nom del mètode. És important que descrigui el que fa el mètode.
L'exemple anterior arguments especifica els paràmetres que acceptarà la funció, que es declaren de la
manera següent:
tipus_dades identificador,
tipus_dades identificador,
tipus_dades identificador
Encara que molts llenguatges (com C o PASCAL) donen la possibilitat de decidir per cada argument
d'una funció o un mètode si estem passant-lo per valor o per referència, en Java no es dóna aquesta
possibilitat:
• Els arguments que són objectes es passen tots per referència (el que s'està passant al mètode
és una referència a l'objecte: l'identificador d'objecte o object identifier, mentre que en C++ es fan
servir les adreces físiques de memòria). Quan parlem de referència volem dir que no es copia el
valor de l'objecte sinó que només es copia la referència.
• Els arguments que no són objectes (int, float, ...) es passen tots per valor (és a dir, s'està
passant una còpia del valor d'aquella variable al mètode).
Finalment, el bloc de codi, com ja hem vist, consisteix en una o més sentències.
• Si la classe és la classe principal del programa, és a dir, la primera classe que es crida i que
inicia el tractament del programa, l'inicialitzador és una funció especial (anomenada main en el
cas de les aplicacions i init en el cas dels applets). Veurem la definició i ús d'aquestes funcions
en el capítol 5 d'aquest mòdul.
• Si la classe és una de les classes que utilitza el programa per a instanciar objectes, llavors la
classe ha de tenir un o varis mètodes, anomenats constructors. Veurem la definició i ús de
constructors en el mòdul 3 d'aquests materials.
Pàgina 28 de 87
Curs Programació Java nivell bàsic.
Les declaracions de variables es poden col·locar en qualsevol lloc del codi sempre i quan precedeixin l'ús
de la variable. Malgrat tot, la pràctica més comuna és declarar-les al principi de cada bloc de codi, amb
excepció de les variables que fem servir com a índexos en bucles for, que es solen declarar en la
mateixa sentència for.
...
public int calculaCost(int preu, int nombreProductes)
{
int total = 0;//declaració de la variable total
//amb valor inicial zero.
float iva; //declaració de la variable iva,
//sense valor inicial.
total = preu * nombreProductes;
iva = 1.16;
Aquestes regles d'àmbit permeten definir els espais d'àmbit. És a dir, les regions on una variable, un
atribut o un mètode serà visible i s'hi podrà accedir. El primer espai d'àmbit és el local, l'espai restringit
fora del qual no es pot veure. El segon és el global, és a dir, tot l'espai.
En Java, les variables definides dins d'una funció membre són locals d'aquesta funció, per la qual cosa
es pot fer servir aquest mateix nom de variable en funcions membre diferents com es mostra en
l'exemple següent:
class LaMevaClasse
{ int i; // variable membre
int mètode1()
{ int j; // variable local
//tant i com j són accessibles des d'aquest punt
return 1;
}
int mètode2()
{ int j; // variable local
// tant i com j són accessibles des d'aquest punt
return 2;
}
}
Pàgina 29 de 87
Curs Programació Java nivell bàsic.
En canvi, la variable i té un àmbit global: es pot utilitzar en tots els mètodes de la classe. Per això també
es diu que i és una variable membre de la classe.
• public implica que un mètode o atribut és visible des de qualsevol classe (àmbit global).
• protected restringeix l'àmbit del mètode o atribut a la pròpia classe i a les seves hereves.
Pàgina 30 de 87
Curs Programació Java nivell bàsic.
En aquest capítol veurem com programar aplicacions molt senzilles en Java, amb la particularitat que
quasi no utilitzarem objectes: utilitzarem Java com si fos un llenguatge procedimental, com PHP, C o
Pascal.
Fins ara havíem vist (a l'exemple del HelloWorld) com escriure missatges per pantalla, amb el mètode
System.out.println.
• Com comprovar que el nombre d'arguments amb què s'ha executat l'aplicació és el correcte.
• Podem veure que la forma de comprovar el nombre correcte d'arguments és mirant la longitut de
la taula d'arguments (length). Totes les taules o matrius en Java tenen associada la seva
longitut.
• També es veu com obtenir els arguments. Totes les taules en Java començen en la posició 0.
Així doncs, el primer argument de l'aplicació és el args[0], el segon argument args[1], etc.
• Cada argument és una cadena, però en el nostre cas necessitem el valor numèric que aquestes
cadenes representen. Això es fa amb la crida al mètode parseInt de la classe Integer.
• Encara que utilitzen el mateix símbol, no hem de confondre l'operador de suma (+) amb
l'operador de concatenació (+). A l'exemple veiem tots dos casos: primer hi ha una suma de
nombre_1 i nombre_2, i després es construeix un missatge concatenant cadenes i nombres.
2.6.2 Exercicis
Pàgina 31 de 87
Curs Programació Java nivell bàsic.
Fer un programa anomenat MaxInt que obtingui l’element de valor màxim d’una taula de int’s. La taula
es definirà com a un atribut estàtic de la classe, no pas rebent les dades com a paràmetre.
Pàgina 32 de 87
Curs Programació Java nivell bàsic.
3 Java, el llenguatge OO
Ja hem vist com programar en Java com si fos un llenguatge clàssic. Però la potència de Java es troba
en la seva orientació a objectes. En aquest capítol veurem amb detall com treballar amb objectes i
classes en Java, i com es fa l’herència. També veurem altres aspectes del llenguatge: com organitzar
les classes en paquets (packages), com treballar amb excepcions i com tracta Java l'entrada/sortida.
En aquest capítol veurem primer com es declaren les classes en Java. També veurem els modificadors
que es poden aplicar a les definicions de les variables, els mètodes i les classes.
Després veurem com instanciar classes per a obtenir objectes, com utilitzar objectes, com accedir als
seus atributs i mètodes, com comparar objectes i com copiar-los.
A continuació veurem amb més detall com treballar amb els objectes més usuals en Java: els strings i
els wrappers i veurem com funcionen les matrius d'objectes.
Finalment veurem una altra manera de programar aplicacions Java, creant objectes programa.
class <nom_de_la_classe>
extends <nom_de_classe_pare>
implements <nom_interfície>
{
declaració_atributs
declaració_mètodes
inicialitzador_de_la_classe
}
En aquest capítol tractarem només classes sense herència, per la qual cosa no apareixeran a les nostres
classes les paraules reservades extends o implements.
Les declaracions dels atributs de la classe són com qualsevol declaració de variables. Les declaracions
dels mètodes de la classe són declaracions de funcions, com les que s'han vist al mòdul anterior.
• atributs:
Pàgina 33 de 87
Curs Programació Java nivell bàsic.
• mètodes:
o el càlcul de l’autonomia del vehicle: donada una quantitat de carburant (en litres),
retornar els quilòmetres que aquest vehicle podria recórrer.
Pàgina 34 de 87
Curs Programació Java nivell bàsic.
3.1.2 Modificadors
Un modificador és una paraula reservada que afecta el temps d'existència o la visibilitat d'una classe,
variable o mètode.
Java posseeix modificadors d'emmagatzamament, de temps d'existència i uns altres utilitzats per a
canviar l'accés d'altres classes a unes classes i membres determinats.
De manera predeterminada, una classe i els seus membres només són coneguts per les altres classes
dins d'un mateix paquet.
Quan s'aplica a una classe, indica que la classe no s'ha implementat completament i que no es pot
instanciar. Si s'aplica a una declaració de mètode, significa que el mètode no està complet i que
s'acabarà d'implementar en una subclasse. Atès que la funció no té implementació, la classe no pot
instanciar-se i s'ha de declarar abstracta. És a dir, si una clase té encara que sigui només un mètode
abstracte, ha de ser declarada com abstracta, però no necessàriament tots els mètodes d’una
clase abstracte ho han de ser. Un exemple de clase abstracte podria ser Figura.
static
Serveix per a declarar atributs o serveis de classe. Les variables estàtiques s'usen sovint per guardar
informació global de seguiment sobre les instàncies d'una classe. Els mètodes també es poden declarar
estàtics. Generalment fem servir classes totalment estàtiques (classes en què atributs i mètodes són
estàtics) quan volem modelar una entitat única. Fem servir atributs estàtics quan només volem una còpia
única d'una variable i quan volem fer un seguiment del nombre d'instàncies que s'han creat.
synchronized
Modificador només per a aplicacions que necessitin el paral.lelisme dels threads de Java. Un mètode de
tipus synchronized només permet que un fil (thread) executi aquest mètode a la vegada. Això evita
que dues tasques en execució es desfacin el treball entre elles. Els mètodes de tipus synchronized es
predeterminen com no estàtics, però poden declarar-se estàtics. No és aplicable a classes o atributs.
final
Pàgina 35 de 87
Curs Programació Java nivell bàsic.
Indica que una variable local o un atribut no pot alterar-se en una subclasse. S’utilitza principalment com
a constant simbòlica. Els mètodes i les classes també es poden declarar final. Un mètode d’aquest
tipus no pot redefinir-se i una classe no pot derivar-se tampoc per crear subclasses. Tot i així l’ús més
freqüent del modificador final és pels atributs, indicant, com hem dit, que no es podran modificar, és a dir,
de fet indiquen que l’atribut és una constant.
Qualsevol classe pot accedir a una altra classe pública. No obstant això, qualsevol altra classe que
necessiti l'applet no cal que sigui pública mentre sigui accessible. Els mètodes i atributs de classes
públiques que s'han declarat com públics permeten ser accedits per altres classes. Si els membres d'una
classe no pública (predeterminada) es declaren públics, aquests membres seran accessibles per a la
resta de classes del paquet.
private
Permet l'accés només als membres d'una classe. D'aquesta forma cap altra classe pot efectuar crides a
mètodes o accedir directament a atributs.
protected
Només permet l'accés a la classe i a les subclasses (i a les altres classes dins el mateix paquet -
package- on es troba la classe actual). Els mètodes es creen a vegades dins d'una classe per motius
d'utilitat (és a dir, perquè s'usin només dins de la mateixa classe i classes relacionades i no perquè se'n
faci un ús indiscriminat). Declarar mètodes d'utilitat protected permet que no només els utilitzi la classe
sinó també les subclasses i altres classes del mateix paquet.
Pàgina 36 de 87
Curs Programació Java nivell bàsic.
Tots els constructors han de tenir com a nom el nom de la classe. La única diferència entre els diferents
constructors d'una classe són els paràmetres del constructor, que poden permetre inicialitzar l'objecte
instanciat de diferents maneres.
Per exemple:
class Persona
{ private int num_dni;
private String nom;
private String adreça;
Per defecte Java posa a totes les classes el constructor sense paràmetres que crea instàncies de la
classe amb els atributs inicialitzats a valors predefinits. És a dir, la classe Persona que acabem de
definir té realment tres constructors: Persona(int pdni), Persona(int pdni, String pnom) i
també Persona(). Si volem que el constructor per defecte de Java (el constructor sense paràmetres)
faci el que nosaltres volem i no el que Java té per defecte, podem afegir a la nostra classe un constructor
sense paràmetres, de manera que estem redefinint un mètode ja existent.
Si en algun fragment de codi volguéssim utilitzar la classe Persona que acabem de definir, hauríem de
fer:
...
Persona p;
...
Però només definint una variable de tipus Persona no tenim encara un objecte. Hem de crear la instància
de la classe Persona:
...
Pàgina 37 de 87
Curs Programació Java nivell bàsic.
p = new Persona(12345678);
...
La sentència new cridarà només un dels constructors de la classe, aquell que tingui el mateix número i
tipus de paràmetres que apareixen en el mateix ordre. A l'exemple, la sentència new escollirà el
constructor Persona(int pdni) entre els 3 constructors de la classe Persona.
Pàgina 38 de 87
Curs Programació Java nivell bàsic.
objecte.nom_atribut
objecte.nom_mètode(paràmetres)
essent objecte, al igual que en el cas anterior, una variable que fa referència a un objecte.
Hi ha un cas especial: el dels atributs i serveis de classe (les responsabilitats de classe). En aquest
cas són atributs i mètodes als quals es pot accedir sense tenir una instància. Són els atributs o mètodes
definits com Static. L'accés es fa en aquests casos posant el nom de la classe en comptes d'una
variable. Ja hem vist un exemple d'això:
Integer.parseInt("12345")
En aquest exercici veurem com un objecte pot ser utilitzat per un altre objecte, fent que a la classe
Persona de l’exemple anterior, l’adreça sigui un objecte especial en comptes d’un simple String.
1. realitzar la declaració de la classe Adreça. Aquesta classe té com a atributs la localitat, el codi
postal i el carrer. Com a mètodes, tindrem el constructor (amb tres paràmetres que corresponen
als atributs de la classe), un mètode de consulta per a cada atribut i un mètode toString que
retorna en una cadena l’adreça sencera amb el format "Carrer – Codi Postal - Localitat".
2. Modificar la declaració de la classe Persona per tal que usi un objecte de la classe Adreça per a
emmagatzemar la informació de l’adreça, en comptes de fer-ho amb un String
Més del mateix, però ara fent servir la classe Vehicle de l'exercici 3.1. El que farem és que la matricula
del vehicle sigui un objecte especial, en comptes d'una simple cadena de caràcters.
Pàgina 39 de 87
Curs Programació Java nivell bàsic.
2. Modificar la declaració de la classe Vehicle per tal que usi un objecte de la classe Matricula
per a emmagatzemar la informació de la matrícula, en comptes de fer-ho amb un String.
...
Persona p1 = new Persona(12345678, “Juan Garcia”);
Persona p2 = new Persona(12345678, “Juan Garcia”);
...
if (p1==p2)
{ ...
}
...
podem pensar que la comparació ens dirà que efectivament p1 i p2 són iguals. Però no és així.
Totes les variables que són objectes no tenen l'objecte dins seu, tenen un identificador d'objecte (object
identifier).
L'operador == només veu el "valor" de les dues variables, és a dir, els identificadors. Com que cada
variable fa referència a un objecte diferent, els identificadors d'objecte són diferents i l'operador == dirà
que són diferents.
Això és així perquè és impossible preparar l'operador == per a poder comparar tots els objectes, tant els
que pertanyen a classes de Java com els que pertanyen a classes creades pel programador.
Són, doncs, les classes, les que han de proporcionar un mètode que digui si dues instàncies de la classe
són iguals o no.
En Java totes les classes defineixen el mètode equals, que permet comparar objectes i dir si són iguals
o no.
Amb aquest mètode estem dient que dos objectes de la classe Persona són iguals si el número de DNI
és igual.
...
Persona p1 = new Persona(12345678, “Juan Garcia”);
Persona p2 = new Persona(12345678, “Juan Garcia”);
...
if (p1.equals(p2)
{ ...
}
...
Compte que amb aquesta definicio p3 = new Persona (12345678, “Maria Perez”) també serà igual a p1 i
p2.
Pàgina 40 de 87
Curs Programació Java nivell bàsic.
...
podem pensar que tenim ara dos variables, cadascuna amb un objecte Persona amb el dni número
12345678 i nom Juan Garcia. Però no és així.
L'operador d’assignació = (a l'igual de l'operador ==) només veu el "valor" de les dues variables, és a dir,
els identificadors d'objectes. És a dir, el que ha fet és que persona2 tingui com a identificador d'objecte el
mateix que persona1. Això vol dir que a partir d'aquest moment persona1 i persona2 fan referència al
mateix objecte, i tots els canvis que es facin sobre persona1 afectaran a persona2.
Això és així perquè és impossible preparar a l'operador = per a poder fer còpies de tots els objectes, tant
els que pertanyen a classes de Java com els que pertanyen a classes creades pel programador.
Són, doncs, les classes, les que han de proporcionar un mètode que creï còpies d'instàncies de la classe
En Java totes les classes defineixen el mètode clone, que permet crear una còpia (un clon) de
l'objecte.
Amb aquest mètode el que fem es retornar un objecte nou de trinca amb el número de dni de l'objecte
original.
...
Què ha passat amb l'objecte que abans referenciava persona2? Si no hi ha cap altra variable o objecte
que faci referència a ell, serà destruït automàticament pel Garbage Collector de la Màquina Virtual de
Java.
Pàgina 41 de 87
Curs Programació Java nivell bàsic.
En concret, veurem:
• La classe String
Aquesta classe proporciona gran quantitat de mètodes que permeten treballar sobre cadenes. Els
trobareu tots a la especificació J2SE, a A la llista següent teniu alguns dels mètodes més importants que
es poden utilitzar sobre qualsevol objecte String:
String substring(int pos_inici, pos_fi) retorna una subcadena (substring) formada per
tots els caràcters que hi ha entre la posició
pos_ini i la posició pos_fi -1. Es considera que
el primer caràcter del string és la posició 0
Pàgina 42 de 87
Curs Programació Java nivell bàsic.
Com que els strings s'utilitzen tant, hi ha tres formes de crear objectes de la classe String:
• Mitjançant els constructors de la classe. Per exemple: a = new String("hola!").
• Mitjançant mètodes generadors d'strings, és a dir, mètodes que retornen un string nou de
trinca. Hi ha moltíssims mètodes en Java que generen strings. De fet, tots els objectes de Java
tenen un mètode toString() que retorna alguna mena de representació de l'objecte en forma
de cadena de caràcters. Per exemple: a = Float.toString(134.2846).
• Escrivint una cadena de caràcters entre cometes dobles ("). Per exemple: a = "Hola!".
Els tipus bàsics de Java tenen uns tipus corresponents en forma d'objecte: són els wrappers:
int Integer
float Float
double Double
char Character
long Long
short Short
boolean Boolean
byte Byte
Totes aquestes classes es troben al paquet java.lang (a l'igual de la classe String). Com que seria
molt llarg parlar de cadascuna d'elles i dels seus mètodes, parlarem d'elles en general. Si teniu algun
dubte sobre algun mètode particular, podeu consultar la documentació.
Com podem passar del tipus bàsic a l'objecte wrapper corresponent? Totes aquestes classes tenen
entre els seus constructors un que permet crear un objecte amb un valor del tipus bàsic. Per exemple, el
pas de int a Integer es fa així:
int a = 100;
Integer obj_a;
...
obj_a = new Integer(a);
Com passar de l'objecte wrapper al tipus bàsic? Totes aquestes classes tenen un mètode
<nom_tipus>Value(), on <nom_tipus> l'heu de substituir pel nom del tipus bàsic corresponent. Un
exemple seria:
float b;
Pàgina 43 de 87
Curs Programació Java nivell bàsic.
Els wrappers numèrics tenen fins i tot mètodes <nom_tipus>Value() per als altres tipus numèrics, la
qual cosa permet fer conversions entre tipus numèrics:
int a;
Float obj_b = new Float(3.14159);
...
a = obj_b.intValue();
Com ja hem avançat, totes les classes de Java tenen definit el mètode toString(). Les classes
wrappers, a més a més, tenen definit aquest mètode:
int a = 100;
String str;
...
str = Integer.toString(a);
Cada classe wrapper defineix un o més mètodes que poden "analitzar" (parse) una cadena i obtenir el
valor numèric. En les classes numèriques hi ha dos mètodes:
Pàgina 44 de 87
Curs Programació Java nivell bàsic.
a = Integer.parseInt(str);
Pàgina 45 de 87
Curs Programació Java nivell bàsic.
Quan a l'anàlisi de l'string es troba un error al format, es genera una excepció. Per exemple, la cadena
"345b7" donaria una excepció al intentar fer la conversió a un número.
• En el seu mètode main rebi com a arguments en línia de comandes totes les dades associades
a un vehicle més la quantitat de litres de carburant que té al dipòsit .
• Crea un objecte Vehicle, al qual li farà calcular la seva autonomia (el nombre de quilòmetres
que pot recórrer amb els litres de carburant que té al dipòsit).
Després d'aquesta declaració es pot consultar i modificar qualsevol de les posicions de la taula.
• En el cas dels objectes això és una mica més complicat, ja que la declaració següent:
crea un vector d'identificadors d'objectes Integer, no un vector d'Integers pròpiament dits. És a dir, hem
creat una taula, però no s'han creat els tres objectes Integer. Això és perque cada posició d'una taula
actua com si fos una variable, i com ja hem dit, en Java les variables que referencien a objectes només
tenen un identificador de l'objecte, no l'objecte.
Un cop es crea una taula d'objectes, s'han d'anar creant un a un tots els objectes que hi seran "a dins".
A l'exemple:
Fer una classe amb mètode main tingui un String amb un contingut de 10 paraules separades per punt i
coma, és a dir, quelcom com del tipus “paraula1;paraula2; ... ; paraula10” i cridi a un mètode private
que retornarà una taula amb les deu paraules. Podeu fer servir el debugger per comprovar que el
resultat sigui correcte, o bé fer un nou bucle per imprimir les 10 posicions de la taula per la consola, per
comprovar que el parsejat de l’string ha estat correcte.
Es pot fer a partir dels mètodes ja explicats de la clase String, o bé fer servir un mètode no explicat de la
clase String.
Pàgina 46 de 87
Curs Programació Java nivell bàsic.
3.2 Herència
Fins ara hem vist com crear classes des de zero. Però de vegades ens podem trobar una classe que és
molt semblant a una altra ja existent (i, el més important, que ja sabem que és lliure d'errors).
En aquests cassos és molt útil utilitzar el mecanisme de l'herència, que ens permet crear una nova
classe només definint què la diferència d'una altra ja creada.
En aquest capítol veurem com es pot fer herència simple en Java i com es pot simular l'herència
múltiple amb les interfícies de Java.
Tota classe que hereti d'una altra ha d'afegir a la capçalera de la seva definició la paraula reservada
extends junt amb el nom de la classe de la qual vol heretar:
class <nom_de_la_classe>
extends <nom_de_classe_pare>
{
...
A partir d'aquell moment, la classe "filla" passa a tenir tots els mètodes de la classe "pare". Així doncs, a
la definició de la classe filla només han d’aparèixer:
Però de vegades volem que el mètode que estem modificant faci les coses que ja feia i, a més a més, les
que definirem en el fill. En Java això s'aconsegueix fent una crida al mètode de la classe "pare" de la
manera següent:
super.<nom_del_mètode_pare>(paràmetres);
La paraula reservada super ens permet fer referència a la classe "pare". No només la podem fer servir
per a estendre la definició d'un mètode del pare, sinó també en la definició d'altres mètodes nous de la
classe.
La crida al constructor de la classe "pare" també es pot fer amb la paraula super de la manera següent:
super(paràmetres);
Això ens pot servir per a definir el constructor de la classe "filla" a partir del de la classe "pare".
Pàgina 47 de 87
Curs Programació Java nivell bàsic.
class DNI
{ protected int num_dni;
DNI (int xifres)
{ num_dni = xifres;
}
Hem afegit a la classe els mètodes equals, clone i toString que, com ja hem dit, tenen totes les
classes Java. Encara que no és obligatori que les nostres classes tinguin definits aquests mètodes, és bo
definir-los. Hem definit la visibilitat de l'atribut num_dni com a protected, en comptes de private per
tal que les subclasses de DNI puguin treballar amb aquest atribut.
En Java totes les classes que no hereten explícitament d'una altra classe, hereten de java.lang.Object
De fet, els mètodes equals, clone i toString són mètodes de la classe Object que hem redefinit
per a adaptar-los a les nostres necessitats. Ja que la classe DNI per si mateixa ja seria un exemple
d'herència simple. Però veurem de tota manera com definir una subclasse a continuació.
Pàgina 48 de 87
Curs Programació Java nivell bàsic.
Quins mètodes haurem de redefinir? Hem de redefinir el constructor perquè calculi la lletra a partir de les
xifres. El mètode getDNI el deixem com està: si ha de tornar el DNI només s'han de retornar les xifres.
El mètode equals no s'ha de redefinir: com que la lletra depèn de les xifres, comparant només les xifres
podem dir si dos NIF són el mateix o no. Hem de redefinir el mètode clone per tal que faci una còpia
d'un NIF, no d'un DNI. Finalment hem de redefinir el mètode toString perquè retorni les xifres junt amb
la lletra del NIF.
El resultat és el següent:
//redefinim el constructor
NIF (int xifres)
{
super(xifres); //Cridem al constructor de
// DNI perquè inicialitzi
// l'atribut num_dni
lletra_nif=calcula_lletra();
}
//mètode auxiliar
private char calcula_lletra()
{
// calculem la lletra amb el ròssec de la divisió entera.
return (taula_lletres[(num_dni % 23)]);
}
//mètode nou
public char getLletra()
{
return (lletra_nif);
}
Pàgina 49 de 87
Curs Programació Java nivell bàsic.
return (super.toString()+lletra_nif);
}
}
D’aquesta manera hem definit NIF només dient les diferències respecte de la seva superclasse.
La superclasse abstracte Figura que pot tenir com a subclasses Cercle, Quadrat ...
La superclasse Persona, que pot tenir com a subclasses Treballador, Alumne, i a la seva vegada
Treballador pot tenir com a subclasses PAS i PDI. Farem aquest exemple més endavant, quan vegem el
JCF.
Una classe abstracta pot tenir mètodes abstractes, és a dir, que NO tenen implementació, sinó només
signatura. Si alguna classe té un mètode abstracte és obligatori que la classe sigui abstracte.
Qualsevol subclasse d’una classe abstracte ha de implementar obligatòriament tots els mètodes
abstractes de la superclasse.
Una classe abstracta pot tenir mètodes NO abstractes, és a dir, que SI tenen implementació, i que no
necessiten ser redefinits (tot i que poden ser-ho), per les subclasses filles.
Un exemple de classe abstracte podria ser en una organització la classe Persona, ja que de fet sempre
es consideraran les persones amb un rol determinat dintre de l’organització, ja sigui Treballador, Client,
Becari ...
Crear l'aplicació QuinNIF. Aquesta aplicació rep com a argument un nombre de DNI. Amb aquest DNI
l'aplicació crea un objecte de la classe NIF, que calcularà la lletra automàticament. Aquesta lletra es
mostrarà per pantalla.
Pàgina 50 de 87
Curs Programació Java nivell bàsic.
A partir d'aquest exercici simularem els tipus de comptes d’un sistema bancari: Compte Corrent, de
Crèdit, d’Estalvis i de Gran Rendabilitat.
Per tal de fer això anirem construint pas a pas una jerarquia d’herències utilitzant classes abstractes,
interfíces, agregacions, polimorfisme, sobrecàrrega i reescritura de mètodes. Ho farem als exercicis 3.7,
3.9, 3.10 i 3.11
A més dels mètodes indicats en el diagrama, hi haurà els corresponents per accedir als atributs.
Creeu aquests mètodes accessors. Feu que el mètode per modificar el saldo només el pugui
cridar el mateix objecte.
L’atribut qttInicial serà una propietat de classe, i establirà la quantitat mínima amb la que s’ha
d’obrir un compte. Els mètodes per consultar i modificar aquest atribut també han de ser
utilitzables només pel propi objecte.
Creeu un parell de constructors per a la classe. Un que admeti com a paràmetre només l’String
que indicarà el número de compte, i l’altre que a més permetrà crear-lo amb una quantitat inicial
decidida per l’usuari (superior a l’establerta per la propietat qttInicial).
Implementeu el mètode toString perquè aparegui la informació del Compte per pantalla (número
de compte i saldo).
Implementeu els dos mètodes indicats al diagrama. Només han de sumar o restar la quantitat
indicada al saldo que hi hagi. De moment NO s’ha de comprovar que no s’intenti treure més del
saldo disponible.
Implementeu també un ‘main’ d’aquesta classe per provar les diferents operacions que heu creat i
que funcionen correctament.
Continuem amb el sistema bancari que hem començat a l'exercici 3.7 En aquest exercici estendrem la
classe principal.
Un banc no té només un tipus de compte bancari. Definim alguns tipus de comptes nous basant-nos
amb la classe que ja hem creat, i que disposa de les operacions bàsiques per qualsevol tipus de
compte. També farem algunes modificacions a la classe CompteBancari.
Pàgina 51 de 87
Curs Programació Java nivell bàsic.
En el primer pas hem definit que el mètode setSaldo sigui només accessible per objectes de la classe
CompteBancari. Modifiqueu l’accés de manera que les classes que hereten també el puguin utilitzar.
El mètode toString de la classe CompteBancari s’heretarà. Ens interessaria que tregui quin tipus de
compte és en cada cas (Corrent, d’estalvis,...) sense que tinguem que rescriure’l per cada subclasse.
Busqueu a l’API (al package java.lang) un mètode que us retorni la classe de l'objecte amb el qual
treballeu i després obteniu el seu nom.
La classe CompteCorrent disposa d’una propietat xecsEmesos que ens indica si aquell l’usuari
d’aquell compte ha demanat un talonari de xecs o no. Ens interessa que els mètodes accessors
d’aquesta propietat no puguin ser reescrits per ningú que hereti d’aquesta nova classe.
Si volem que els constructors definits en la superclasse funcionin a les subclasses és necessari que els
construïm a la subclasse, però com a codi només tindran la crida al constructor de la superclasse. Això
és degut a què si no especifiquem res, els constructors sempre intenten cridar al default constructor de
la superclasse, que en el nostre cas no existeix (hem definit dos constructors diferents al default, que no
portaria arguments). Això també ho haureu de fer amb la classe CompteEstalvis.
Necessitarem un parell de mètodes nous per calcular l’interès generat i per acumular-lo al saldo del
compte. El mètode per calcular l’interès volem que no es pugui reescriure (només hi ha una forma de
calcular l’interès, i és la que escrivim en aquesta classe). El mètode per acumular-lo també hauria de ser
del mateix estil, però més endavant el sobrescriurem, de forma que deixeu-li llibertat per fer-ho.
A les dues noves classes creades els hi afegiu un main per poder provar-les per separat. En acabar,
creeu una nova classe ‘TestCB.java’ on utilitzareu objectes de les tres classes. No us compliqueu la
vida demanant les dades com a arguments, feu les assignacions directament dins del codi.
Pàgina 52 de 87
Curs Programació Java nivell bàsic.
1.- Crear una classe Figura amb dos mètodes, perímetre() i àrea (). Penseu si la classe ha de ser o no
abstracta.
2.- Crear una classe Rectangle que tingui com a atributs els 2 punts (x1,y1) i (x2, y2) que el
defineixen en l’espai. Com que un rectangle és una figura, farem que extengui figura i, per
això, caldrà implementar el mètode perímetre 2* ((x2-x1) + (y1-y2)) i també el mètode àrea
(x2-x1) * (y2-y1).
3.- Crear una classe Cercle que tingui com a atributs el punt (x1,y1) del centre i el radi r que el
defineixen en l’espai. Com que un cercle és una figura, farem que estengui figura i, per això,
caldrà implementar el mètode perímetre 2*Pi*r i també el mètode àrea PI * r * r. Compte amb
la definició de la lletra PI. Escull la millor forma de fer-ho.
Pàgina 53 de 87
Curs Programació Java nivell bàsic.
3.2.2 Interfaces
Un interface és un conjunt de declaracions de mètodes, sense definició. També poden definir constants
que són implícitament public, static i final i han d’estar inicialitzades en la declaració. Els mètodes
defineixen el tipus de conducta. Totes les classes que implementen una interface han de proporcionar
una implementació dels mètodes de la interface.
Com que els mètodes d'una interfície estan encara per implementar, quan una classe inclou una
interfície es diu que l'està implementant, ja que a la definició de la classe han d’aparèixer els mètodes
de la interfície i els hem d’implementar.
Una classes de java pot heretar d’una única classe, però en canvi pot implementar totes les interfícies
que vulgui.
Tota classe que implementi una o vàries interfícies ha d’afegir a la capçalera de la seva definició la
paraula reservada implements junt amb el nom de les interfícies que implementi:
class <nom_de_la_classe>
extends <nom_de_classe_pare>
implements <nom_de_la_interfície_1>
[,<nom_de_la_interfície_2>...
... , <nom_de_la_interfície_N>]
{
...
}
Quina diferència hi ha entre una interface i una clase abstract? Es semblen molt, de fet en algunes
circumstàncies són intercanviable, però tenen també importants diferències:
1. Una classe NO pot heretar de dos classes abstract, però sí pot heretar d’una classe (sigui o no
abstract) i implementar una interface, o bé implementar dos o més interfaces.
2. Una classe NO pot heretar mètodes implementats d’una interface, tot i que sí constants.
3. Els interfaces permeten molta més flexibilitat per aconseguir que dues classes tinguin el mateix
comportament.
4. Els interfaces permeten publicar el comportament d’una classe desvelant un mínim d’informació.
Aquest quart motiu és la raó principal per la qual a java es fa un ús intensiu dels interfaces dintre del món
dels “estandards”. Sun defineix un estandard, per exemple per accedir a bases de dades, per manegar
col·leccions d’objectes ... mitjançant l’especificació de tot un seguit de interfaces. Sun mateix proveeix
habitualment classes que implementen aquests interfaces (anomenada implementació de referència),
però queda el camí obert a que altres fabricant programin altres classes que implementin els mateixos
interfaces, és a dir, que proveeixin la mateixa funcionalitat. Aleshores les classes clients d’aquests
interfaces poden fer servir una o altre implementació segons els convingui, sense necessitat de modificar
el codi.
La definició d'una interfície és molt similar a la definició d'una classe, amb la particularitat que tots els
mètodes no tenen codi associat.
definició_mètodes_abstractes
}
Les constants que es defineixen en una interfície son "heretades" per les classes automàticament, és a
dir, les classes que implementen una interfície amb constants poden accedir a les constants com si
fossin a dins la classe.
Pàgina 54 de 87
Curs Programació Java nivell bàsic.
Els mètodes d'una interfície són tots abstractes per defecte, per la qual cosa no fa falta que posem el
modificador abstract a cada mètode, encara que es pot posar si es vol.
El Java, però, és un dels llenguatges orientats a objectes que no té herència múltiple, peró la pot simular
mitjançant un mecanisme propi: les interfícies.
En l'exemple que acabem de posar del Monovolum, podríem fer que heretés de Cotxe i que
implementés una interfície Furgoneta, que definís nous atributs com la TARA i el pes màxim amb els
seus mètodes associats.
Però, si hem d'escriure igualment el codi dels mètodes d'una interfície des de zero, per a què serveixen
les interfícies?:
• Quan una classe A implementa una interfície B, tots els objectes de la classe A són també
objectes B. Tenim doncs, la segona propietat de l’herència, que els objectes A es poden fer
passar per objectes B. Per exemple, un Monovolum no només es pot fer passar per Cotxe, sinó
també per Furgoneta.
• Les interfícies defineixen un estàndard per a totes les classes que les implementen: com que tota
classe que implementi la interfície A ha de definir tots els seus mètodes, tots els objectes que
pertanyen a classes que implementen a A tindran disponibles els mètodes d'A. Per exemple, en
el cas de l'interfície Furgoneta tot objecte d'una classe que la implementi tindrà disponible el
mètode getTARA(). Això permet fer codi comú per a qualsevol objecte que "sigui" una
Furgoneta.
En el nostre cas hem escollit que la classe Monovolumen hereti de la classe Cotxe (que ja ha aparegut
a l'exercici 2.1) i implementi una interfície Furgoneta, que encara hem de definir.
Recordem que la classe Cotxe hereta de la classe Vehicle. Doncs, un cotxe té la següent informació
associada:
• Matrícula
• número de places
• extres de confort
Pàgina 55 de 87
Curs Programació Java nivell bàsic.
D'aquesta llista, els tres primers punts són informació que un cotxe té per la seva condició de vehicle,
mentre que els dos últims punts són atributs nous de la classe Cotxe.
Un cop hem vist què és el que té un cotxe, vegem què té una furgoneta. D'una furgoneta ens interessa
saber les característiques que té com a transport de mercaderies:
• la TARA
Furgoneta.java
public interface Furgoneta
{
//no hi ha constants
//declaració de mètodes
Al declarar aquests quatre mètodes, estem obligant a tota classe que implementi la interfície ha de tenir
dins seu uns atributs amb la informació de la TARA i el PMA, siguin quins siguin els seus noms.
Monovolumen.java
class Monovolumen extends Cotxe implements Furgoneta
{
//declaració d'atributs
protected int valor_TARA, valor_PMA;
//declaració de mètodes
Pàgina 56 de 87
Curs Programació Java nivell bàsic.
valor_TARA = tara;
valor_PMA = pma;
}
Pàgina 57 de 87
Curs Programació Java nivell bàsic.
3.3 Excepcions
En situacions excepcionals com ara una dada d'entrada no vàlida que podria malmetre el programa,
Java fa servir una manera de capturar errors anomenada gestió d'excepcions (exception-handling). La
gestió d'excepcions de Java és similar a la de C++ o Delphi.
L'objectiu principal de la gestió d'excepcions és transferir el control des del punt on s'ha produït l'error a
un gestor d'errors (error-handler) que pugui fer-se càrrec de la situació.
Excepcions en Java
En Java, una excepció és sempre una instància d'una classe derivada de Throwable. En particular,
podem crear les nostres classes d'excepció amb l'herència si la que proporciona Java no satisfà les
nostres necessitats.
La jerarquia Error descriu errors interns i recursos exhaurits en el sistema Java en temps d'execució.
Les condicions d'error d'aquest tipus són molt rars.
En el programa, ens centrem en la jerarquia d'Exception. Aquesta també es divideix en dues branques:
excepcions que deriven de RuntimeException i aquelles que no en deriven. La regla general és
aquesta: Una RuntimeException es produeix perquè s'ha comès un error de programació. Qualsevol
altra excepció es produeix perquè s'ha produït un fet incorrecte, com un error d'entrada o de sortida.
• un accés a una variable que no fa referència a cap objecte (identificador d'objecte = null), és
amb molt la més habitual en Java, la NullPointerException.
Pàgina 58 de 87
Curs Programació Java nivell bàsic.
La idea és que cal canviar la capçalera d'un mètode per a reflectir les excepcions que pot llançar.
Tant si es crida un mètode que llança una excepció (per exemple, el mètode readLine del
DataInputStream) o bé es detecta un error i es llança una excepció amb la sentència throw, s'ha
d'anunciar públicament que el nostre mètode pot llançar una excepció.
Si cap procés de tractament d'errors agafa l'excepció, el programa acaba. Anunciem que el nostre
mètode pot llançar una excepció posant a la capçalera del mètode el següent:
Si un mètode tracta més d'una excepció, s'indiquen totes a la capçalera separades per comes. En canvi,
no cal indicar els errors interns de Java, és a dir, els heretats d' Error.
Les excepcions no heretades de RuntimeException o d'Error són les úniques que hauria de tractar
el programador.
Un cop Java llança una excepció, el mètode que ha provocat l'excepció acaba i el control torna al mètode
més proper en la seqüència de crides que contingui un catch() que inclogui l'excepció.
Vegem un exemple:
class Animacio
{
...
...
}
Creació d'excepcions
El nostre codi pot tenir el problema que no s'adeqüi a les classes d'excepcions estàndards descrites. En
aquest cas, podem crear les nostres classes d'excepcions. Només hem de derivar d' Exception o d'una
classe subordinada com IOException. És comú indicar un constructor predeterminat i un constructor
que contingui un missatge detallat. El mètode toString() de la classe bàsica Throwable imprimeix
el missatge detallat.
Pàgina 59 de 87
Curs Programació Java nivell bàsic.
Ara posarem un exemple del seu ús. La classe FileInputStream (que veurem més endavant) llegeix
un fitxer byte a byte. La marca de fi de fitxer és el -1. El mètode intenta obtenir tot el contingut d'un fitxer
de text dins un String:
/**/
String readData(FileInputStream f) throws FileFormatException
{
...
String text;
...
while (...)
{
if (car == -1)
{
// aleshores hi ha un end of file i llancem un objecte
// de la classe d'excepció apropiada
throw new FileFormatException();
}
....
}
return text
}
Captura d'excepcions
Ja sabem que llançar una excepció és molt simple. La llancem i ens oblidem. La captura és més
complexa.
Si es produeix una excepció i ningú no la captura, Java acaba el programa i mostra un missatge que
indica el tipus d'excepció i la traça de la pila de crides entre mètodes.
try
{ <codi>
}
catch(<tipus_excepció> <variable>)
{ <gestor per a aquest tipus>
}
Si un codi qualsevol del bloc try llança una excepció de la classe indicada a la clàusula catch,
aleshores
Pàgina 60 de 87
Curs Programació Java nivell bàsic.
...
integer iCnt;
integer n;
Stack s;
try
{
for (i=0; i<100; i++)
{
n = s.pop();
out.writeInt(n);
}
}
catch (IOException e)
{
System.out.println("Excepció de lectura de fitxer: " + e);
}
catch (EmptyStackException s)
{
System.out.println("Excepció de pila buida: " + s);
}
...
La sentència finally
Quan Java llança un error s'atura el procés de tot el codi en el mètode. Això és un problema si el mètode
local ha adquirit un recurs que només coneix aquest mètode i si aquest recurs ha de ser alliberat. Una
solució seria capturar i tornar a llançar l'excepció però cal alliberar el codi normal i el codi de l'excepció.
Java utilitza la clàusula finally. Dins finally hi ha un codi que s'executarà en funció de si una
excepció es captura o no.
Tant si hi ha excepció com si no n'hi ha, Java executarà la clàusula finally i podrà alliberar els
recursos.
• Si no hi ha excepció, primer s'executa el bloc del try, després el bloc del finally i per últim
continua l'execució des de la primera línia de codi que ve a continuació del bloc del try-catch-
finally.
• Si es llança una excepció, aleshores es captura en la clàusula catch i després s'executa el codi
del finally.
• Si el codi llança una excepció però no és capturada pel catch, aleshores Java executa el codi
del finally i retorna l'excepció a qui hagi cridat a aquest mètode.
Un exemple de la triple sentència try-catch-finaly és el següent:
Pàgina 61 de 87
Curs Programació Java nivell bàsic.
...
boolean fet = false;
int numero;
String cadena = " ";
Graphics g = image.getGraphics();
try {
numero = System.in.read();
if ((numero < 0) || (char)numero == '\n')
fet = true;
else
cadena = cadena + (char)número;
}
catch (IOException e)
{
fet = true;
}
finally
{
g.dispose();
}
...
1.- No es pot obrir un compte amb una quantitat més petita que la inicial.
2.- La imposició ha de ser d’un número >= 0, no pot ser d’un número negatiu.
3.- El reintegre ha de ser d’un número >= 0, no pot ser d’un número negatiu.
Feu que l’excepcio que es llenci no sigui Exception sinó una pròpia, anomenada CompteException que
a més a més del missatge d’error, pugui informar del num de compte en el qual s’ha produït l’error.
Pàgina 62 de 87
Curs Programació Java nivell bàsic.
3.4 Packages
Java permet agrupar classes en una col·lecció anomenada paquet (package). Els paquets són
convenients per a organitzar el treball i per a separar el treball de les llibreries de codi proporcionades
per altri.
Per exemple, ens donen una sèrie de classes útils en un paquet anomenades corejava. La llibreria
estàndard de Java es distribueix en una sèrie de paquets que inclouen java.lang, java.util,
java.net, etc. Els paquets estàndard de Java són exemples d'una jerarquia de paquets. Quan tenim
subdirectoris jerarquitzats en el disc dur, els paquets es poden organitzar per nivells de jerarquia. Tots
els paquets estàndard de Java són dins de la jerarquia de paquets de Java.
Una raó per a jerarquitzar paquets és garantir la unicitat de noms de paquets. Es poden tenir tants nivells
de jerarquització com es vulgui. De fet, per a garantir totalment un nom de paquet únic, Sun recomana
que s'utilitzi un nom de domini d'Internet de la companyia de l'usuari escrit en ordre invers com a prefix
del paquet.
Quan s'escriu un paquet (package), s'ha de posar el nom del paquet a dalt del fitxer font, abans del codi
que defineix les classes del paquet. La sentència package ha de ser la primera de totes en el fitxer, fins i
tot abans de qualsevol comentari. Si el fitxer font no té cap declaració package, Java afegeix les classes
al paquet predeterminat.
Cal recordar que la notació dels paquets segueix el sistema del domini invers, és a dir, primer va el més
genèric (com, per exemple), i a continuació, cada cop és més específic. Per exemple, el paquet
com.java.taules.taulaEnters, ens diu que hi ha una classe o paquet que es diu taulaEnters
dins el paquet taules, que pertany al paquet java, que pertany alhora al paquet com, el més genèric.
Al contrari del que passa amb els noms de les màquines d'Internet (del nom menys específic al mès
genèric: campus.uoc.es és el nom d'una màquina que es diu campus, del domini uoc, que pertany al
domini es).
3.4.1 Ús de packages
Es poden fer servir les classes públiques d'un paquet (package) de dues maneres:
• La primera és indicar simplement el nom complet del paquet, encara que és una opció bastant
pesada. Per exemple:
int i = corejava.Console.readInteger();
java.util.Date today = new java.util.Date();
• La manera més simple i més comuna és utilitzar la paraula clau import. Es pot fer referència a
les classes d'un paquet sense indicar els noms complets. Es pot importar una classe específica o
el paquet sencer. Es col·loca la sentència import abans del codi font de la classe que
s'utilitzarà. Per exemple:
Pàgina 63 de 87
Curs Programació Java nivell bàsic.
o bé...
Normalment, és més simple importar totes les classes d'un paquet. No té cap efecte negatiu en el temps
de compilació o en la mida de codi de manera que generalment no hi ha cap raó per no fer-ho.
Malgrat això, es pot fer servir només l' * per a importar un sol paquet. No es pot fer servir
import java.*;
...
per a importar totes les classes de tots els paquets amb el prefix java.
Aquests subdirectoris no necessiten bifurcar-se directament des del directori arrel; poden separar-se des
de qualsevol directori indicat en la variable CLASSPATH. Quan el compilador troba un fitxer que
s'emparella, comprova que el nom del paquet s'emparelli amb la via d'accés (path) i que el fitxer
contingui una classe pública dins el paquet amb el nom de la classe que es vol fer servir.
Quan es crea un paquet, la nostra responsabilitat és col·locar els fitxers de programa objecte en el
subdirectori apropiat. Per exemple, si es compila un fitxer que comença amb la línia de paquet
acme.util, aleshores el fitxer de la classe resultant s'ha d'ubicar en el subdirectori acme\util. El
compilador no ho farà per nosaltres.
Per exemple, si la classe Card no està definida com a classe pública, aleshores només poden accedir-hi
altres classes del mateix paquet (com CardDeck).
Ara farem que la classe Persona tingui en comptes de l’atribut String Dni, un atribut nif de la classe NIF
creada al 3.6. Per això ficarem les classes del 3.6 en el package edu.ub.rrhh. Caldrà fer que DNI i
Pàgina 64 de 87
Curs Programació Java nivell bàsic.
NIF tinguin un àmbit públic per tal que puguin fer-se servir fora d’aquest package. També hauran de
ser públic els constructors.
Generarem un rrhh.jar amb les classes DNI i NIF (no amb QuinNif, que només és per proves).
Modificarem el projecte de l’exercici 3.2 per tal que faci servir la llibreria rrhh.jar generada en el punt
anterior.
Modificar el private int num_dni de la classe Persona per private NIF nif
Pàgina 65 de 87
Curs Programació Java nivell bàsic.
4 Classes d’utilitat.
Els objecte d’aquesta classe rarament es fan servir de forma aïllada. Normalment s’utilitzen amb en
combinació amb les classes que anem a veure a continuació.
La Classe Calendar té tot un seguit de variables membre i constants (final) que poden resultar molt útils:
La variable int AM_PM que pot prendre dos valors: les constants AM o PM
La variable int DAY_OF_WEEK pot prendre els valors SUNDAY, MONDAY ...
La variable int MONTH pot prendre els valors JANUARY, FEBRUARY ...
La variable membre HOUR es fa servir per indicar la hora del matí o tarda en format 12h (valors 0 a 11)
La variable membre HOUR_OF_DAY es fa servir per indicar la hora del dia en format 12h (valors 0 a 23)
Altres són: DAY_OF_MONTH, DAY_OF_YEAR, WEEK_OF_MONTH, WEEK_OF_YEAR
I altres més: YEAR, MONTH, HOUR, MINUTE, SECOND
La Classe GregorianCalendar afegeix les constants BC i AD com a valors possibles per la ERA per
representar dates abans i desprès de Jesucrist (amen !!!).
Els mètodes més utilitzats de GregorianCalendar són, com no, els diferents constructors.
Pàgina 66 de 87
Curs Programació Java nivell bàsic.
GregorianCalendar (int year, int month, int Crea un gc del any, mes i dia passats com a
dayOfMonth) paràmetres. El mes va de 0 a 11
GregorianCalendar (int year, int month, int El mateix que l’anterior, però fins al minut.
dayOfMonth, int hour, int minute)
boolean before (Date) Indica si la data passada com argument és
anterior a la data representada per l’objecte.
long getTimeInMillis() Milisegons des del 1970
setTimeInMillis (long)
Podem fer modificacions de les diferents propietats (dia, mes, any, hora …) del GC d’una forma ben poc
intuïtiva. Qualsevol esperaria mètodes dels tipus setYear(), setMonth(). En comptes d’això el que
trobem els següents mètodes :
set (int field, int value) Estableix el camp indicat (mes, any …) al valor
indicat. Els valors vàlids per field són les
constants Calendar.ERA, Calendar.YEAR,
Calendar.MONTH …
set (int year, int month, int dayOfMonth) Crea un gc del any, mes i dia passats com a
paràmetres. El mes va de 0 a 11
set (int year, int month, int dayOfMonth, int hour, int El mateix que l’anterior, però fins al minut.
minute)
Podem accedir als valors de les diferents propietats (dia, mes, any, hora …) del GC d’una forma
igualment ben poc intuïtiva. Qualsevol esperaria mètodes dels tipus getYear(), getMonth(). En comptes
d’això trobem el següent solitari i trist mètode:
int get (int field) Obté el valor del camp indicat (mes, any …). Els
valors vàlids per field són les constants
Calendar.ERA, Calendar.YEAR,
Calendar.MONTH …
Podem obtenir, a partir del calendar, el date corresponent (sobre el que per exemple podrem preguntar
before o after), o establir el calendar a partir d’un date.
Una operació molt habitual que demanarem a un GC serà sumar-li dies. Tampoc hi ha un mètode
concret que faci això, sinó un molt més genèric que pot sumar no només dies, sinó també anys, mesos
…
add (int field, int amount) Suma al camp indicat (dia, mes, hora ...) el valor
indicat com amount. Si amount és negatiu,
evidentment, fa la resta.
roll (int field, boolean up) Puja o baixa una unitat el camp indicat a field,
sense modificar els camps de nivell superior. Si
tenim el 20/12/2006 i fem roll del camp mes, es
generarà 20/01/2006 i no pas 20/01/2007
Roll (int field, int amout) Igual que l’anterior, per sumant o restant
l’amount indicat. Tampoc modifica els camps de
nivell superior.
4.1.2.1 Leniency
Per acabar de complicar el que ja de por sí és complicat, apareix aquest concepte de difícil traducció.
Calendar te dos mode per interpretar els seus atributs, lenient i non-lenient. Quan un Calendar
es troba en mode lenient , accepta un rang més ampli de valors en els seus atributs del que són
« legals ». Quan Calendar recalcula els seus camps per exemple per la crida a get(), tots els
Pàgina 67 de 87
Curs Programació Java nivell bàsic.
Quan Calendar no és lenient, llença una exception si hi ha alguna inconsistència en els seus
atributs. Per exemple, un GregorianCalendar sempre produeix valors de DAY_OF_MONTH entre
1 i el número de dies del mes. Un non-lenient GregorianCalendar llençarà una exception quan
calculi qualsevol camp si algun d’ells es troba fora de rang.
Per defecte tot calendari es troba en mode Leniency (el més permissiu), però canviar-ho amb el
mètode setLenient (boolean ).
4.1.3 Exercicis
Pàgina 68 de 87
Curs Programació Java nivell bàsic.
Fer un programet que rebi 3 paràmetres, dia, mes i any, i indiqui si la data representada per aquest 3
dies és menor, major o igual que la data actual.
Possiblement caldrà fer servir el mètode getDate().
Parar especial atenció al cas d’igualtat de dates.
Text: Si es fan servir 4 o més lletres, es posarà el text llarg, sinó l’abreviatura.
Number: El número de lletres és el número mínim de números que sortiran
Month: 2 o menys lletres s’interptre com a número. 3 com a text abreujat i 4 o més com a text sencer.
23/12/2006 “dd’/’MM’/’yyyy”
Dilluns 23 de setembre de 2006 “EEEE dd ‘de’ MMMM ‘de’ yyyy”
08:42:03 “HH:mm:ss”
Pàgina 69 de 87
Curs Programació Java nivell bàsic.
Una de les operacions més habituals en un entorn “aplicació web” és demanar dates (del que sigui),
mitjançant un formulari html, que només entén de strings. Així que és molt important per una banda
saber si l’string introduït té el format demanat (dd/mm/yyyy) per poder convertir-ho en un date que
guardarem a la BD i, per altre banda, també és útil saber convertir un date recuperat de la base de
dades, en un format més llegible.
Atenció amb el tema Lenient. Al igual que a calendar, si no indiquem el contrari, java intentarà “arreglar”
allò que és incorrecte, per exemple, el següent tros de codi, tot i que sembli increïble, NO llençarà cap
excepció, sinó que posarà en d la data corresponent al 01/11/2006.
Cal implementar una classe que rebi com a paràmetre un string representant una data (per
exemple 02/10/2006) i mostri per pantalla el text en català d’aquesta data, és a dir, Dilluns 02 de
octubre de 2006.
Pàgina 70 de 87
Curs Programació Java nivell bàsic.
4.2.1 Introducció
Una col·lecció, també a vegades anomenada contenidor, és un objecte que agrupa múltiples elements en
una sola unitat. Versions prèvies a la 1.2 contenien colleccions com Vector, Hashtable i Array, però no
estaven definides com un autèntic framework.
4.2.2.1 Collection
Interface que defineix el conjunt mínim de mètodes que han de definir totes les demés col·leccions. A
continuació es presenten les que es fan servir més sovint.
int size()
boolean isEmpty()
boolean add (Object element) // opcional
boolean remove (Object element) // opcional
Iterator iterator()
Object[] toArray()
Cal ressenyar que a més a més del constructor buit, es defineix un constructor que rep com a paràmetre
una col·lecció. Aquest constructor és conegut com el constructor de conversió, ja que permet construir
una col·lecció d’un tipus determinat a partir d’una col·lecció de qualsevol altre tipus.
Collection (Collection c) Permet obtenir una col.lecció a partir d’una altre.
Pàgina 71 de 87
Curs Programació Java nivell bàsic.
A més a més del mètodes anteriorment indicats, existeixen els “Bulk” que actuen sobre la totalitat
d’elements, permeten fer unions, interseccions ... una de les que més es fa servir és:
void addAll(Collection c) Afegeix a la coleció tots els objectes de c
For-each.
for (Object o: collection)
{ // fer el que calgui sobre o.
}
Exemple
import ...
class TestCollection
{ public static void main (String[] args)
{ Collection c = new ArrayList();
c.add(new Persona ("Julio", "Peñuela")); c.add(new Persona ("Juan", "Garcia"));
c.add(new Persona ("Alberto", "Albarado"));
for (Object s: c)
{ Persona p = (Persona) s;
System.out.println (p.cognom1);
}
}
}
Recordeu que aquesta sintaxi només funciona a partir de la versió 1.5
Iterators
Fins a la versió 1.4 la única forma de poder recórrer una col·lecció era fer servir el mètode iterator() per
obtenir un objecte iterator i, recórrer aquest. Els dos mètodes bàsics d’aquesta interface iterator són
boolean hasNext() Indica si encara queda algun element per recórrer
object next() Retorna el següent objecte. Caldrà fer cast al
tipus que correspongui
void remove() Elimina el darrer objecte llegit de l’iterador i, en
conseqüència, de la col·lecció. Només es pot
cridar 1 remove per 1 next.
Exemple
class TestCollection
{ public static void main (String[] args)
{ Collection c = new ArrayList();
c.add(new Persona ("Julio", "Peñuela")); c.add(new Persona ("Juan", "Garcia"));
c.add(new Persona ("Alberto", "Albarado"));
Iterator it = c.iterator();
while (it.hasNext())
{ Persona p = (Persona) it.next();
System.out.println (p.cognom1);
}
}
}
Pàgina 72 de 87
Curs Programació Java nivell bàsic.
Si ens conformem amb obtenir un array d’objectes, sense especificar-ne el tipus, podem fer
Object[] o = c.toArray();
Si coneguem el tipus d’objecte de la col·lecció i volem un array d’aquest tipus el que cal fer és:
Per un client d’una classe és molt més clar rebre un Array de Persones que una collecció d’objectes de
les qual no en sap el tipus. I per què no en creem directament l’Array? Doncs per que potser en el
moment de la creació no en sabem quin ha de ser el seu tamany.
4.2.2.2 Set
Set és una col·lecció que no pot contenir elements duplicats. Conté només els mètodes que hereta de
Collection i afegeix la restricció que està prohibit tenir elements duplicats.
class TestCollection
{ public static void main (String[] args)
{ Collection c = new HashSet();
c.add(new Persona ("Julio", "Peñuela"));
c.add(new Persona ("Juan", "Garcia"));
c.add(new Persona ("Alberto", "Albarado"));
Iterator it = c.iterator();
while (it.hasNext()) //L’ordre no és necessàriament el de introducció
{ Persona p = (Persona) it.next();
System.out.println (p.cognom1);
}
}
}
class TestCollection
{ public static void main (String[] args)
{ Collection c = new ArrayList();
c.add("Primero"); c.add("segundo"); c.add("tercero");
c.add("segundo");
c.add("cuarto"); c.add("quinto");
c.add("tercero");
System.out.println("Primera col.lecció");
System.out.println("..................");
for (Object o: c)
{ System.out.println(o);
}
System.out.println("..................");
System.out.println("Segona col.lecció");
Pàgina 73 de 87
Curs Programació Java nivell bàsic.
Iterator it = noDups.iterator();
while (it.hasNext())
{ System.out.println (it.next());
}
}
}
S’ha recorregut la primera col.lecció amb el for each i la segona amb el iterador només per motius
didàctics, ja que qualsevol de les dues col.leccions es podria recòrrer per qualsevol dels dos mètodes.
4.2.2.4 List
Un List és un Collection ordenat que permet accés directe per index. Pot, a més a més, contenir
elements duplicats. A més a més del mètodes heretats de collection, la interface List inclou, entre
d’altres, els següents mètodes:
object get (int index) Retorna l’objecte que es troba en la posició index
object set(int index, Object o) Posa l’objecte en la posició index i retorna l’objecte
que abans hi estava en aquest posició
Int indexOf (Object o) Retorna la 1ª posició en la que es troba l’object o
Int lastIndexOf(Object o) Retorna la darrera posició en la que es troba
l’object o
Creeu una classe Treballador, estenent Persona, i afegint un atribut anomenat contractes que sigui un
col·lecció de Contractes. Escolliu vosaltres mateixos el tipus de col·lecció que voleu fer servir.
Pàgina 74 de 87
Curs Programació Java nivell bàsic.
A la classe Treballador afegiu el mètode getContractes() que retorni un array de contractes Contractes[]
en l’ordre en que han estat introduïts.
A la classe Treballador, a mode de test, afegiu un mètode main, que crei un Treballador amb 3
contractes:
Id Data inici Data fi Sou
1 01/01/2004 31/12/2004 1300
2 01/01/2005 31/12/2005 1350
3 01/01/2006 08/10/2006 1300
i crideu al mètodes Contractes[] getContractes(). Feu servir el debugger per comprovar el contingut de la
resposta del mètode sigui correcte.
4.2.2.6 Queue
No la veurem en aquest curs.
4.2.2.7 Map
Un Map és un objecte que mapeja keys a valors. A continuació es presenten els mètodes més habituals
d’aquest interface
put (String key, Object v) Guarda l’objecte v amb la key indicada
object get (String Key) Retorna l’objecte corresponent a la Key. Caldrà
fer un cast.
remove (String key) Treu l’objecte de la key indicada.
boolean containsKey(String key) Indica si existeix o no la key rebuda com a
paràmetre
boolean containsValue(Object value) Indica si ja es troba aquest objecte en el map.
int size()
boolean isEmpty()
Cal ressenyar que a més a més del constructor buit, es defineix un constructor que rep com a paràmetre
un map. Aquest constructor és conegut com el constructor de conversió, ja que permet construir un Map
d’un tipus determinat a partir d’un Map de qualsevol altre tipus.
Una vegada obtinguts el Collection o el Set corresponent, es poden iterar amb el for each o amb el
iterator.
Multimaps
Pàgina 75 de 87
Curs Programació Java nivell bàsic.
Un Multimap és un Map on a una mateixa key li poden correspondre múltiples values. JCF no inclou cap
interface específica per ells i suggereix implementar-lo fent que el value sigui de tipus List.
Exemple
A continuació es presenta un exemple de creació i recorregut d’un Map.
class TestMap
{ public static void main (String[] args)
{ Map m = new HashMap();
// Aquest és un map xorra, on la key és l'index.
for (int i=0; i < args.length; i++)
{ m.put("key"+i, args[i]);
}
// Accés directe a una key
System.out.println ((String) m.get("key1"));
Import ....
class TestSort1
{ public static void main (String[] args)
{ List l = new ArrayList();
l.add(new Persona ("36570441", "Julio", "Peñuela"));
l.add(new Persona ("20345671", "Juan", "Garcia"));
l.add(new Persona ("23412562", "Alberto", "Albarado"));
Collections.sort(l);
Iterator it = l.iterator();
while (it.hasNext())
{ Persona p = (Persona) it.next();
System.out.println (p.dni);
}
}
}
Pàgina 76 de 87
Curs Programació Java nivell bàsic.
Un altre mecanisme, quan no vulguem o no poguem fer que la classe implementi comparable, o quan
vulguem poder aplicar diferents ordenacions a la mateixa classe, és fer servir Comparators i cridar al
mètode Collections(List, Comparator) on Comparator és una Classe que implementa la interfície
Comparator, que té un únic mètode int Compare (Object o1, Object o2).
class TestSort2
{ public static void main (String[] args)
{ List l = new ArrayList();
l.add(new Persona ("36570441", "Julio", "Peñuela"));
l.add(new Persona ("20345671", "Juan", "Garcia"));
l.add(new Persona ("23412562", "Alberto", "Albarado"));
Comparator comp = new ComparadorPerNomCognom();
Collections.sort(l, comp);
Iterator it = l.iterator();
while (it.hasNext())
{ Persona p = (Persona) it.next();
System.out.println (p.cognom1 + " " + p.nom);
}
}
}
Pàgina 77 de 87
Curs Programació Java nivell bàsic.
Pàgina 78 de 87
Curs Programació Java nivell bàsic.
5 JDBC.
JDBC és un conjunt de mètodes i interfícies que ens permeten accedir i manipular bases de dades.
Gràcies a ells podem utilitzar codi SQL dins del codi Java. Trobareu el tutorial original de sun traduït al
castellà a http://www.programacion.com/java/tutorial/jdbc/
JDBC està pensat per a no tenir que patir sobre el funcionament del SGBD que volem utilitzar, ja que per
a nosaltres, tot el procés de comunicació ens serà transparent. L'encarregat de entendres amb el SGBD
serà el controlador (driver) específic de cada JDBC.
Caldrà disposar d’un driver, ja sigui genèric, o ja sigui propietari (com el driver oci d’oracle).
L’api JDBC va ja per la versió 3.0, tot i que en el curs s’explicaran només les característiques més
bàsiques, incloses fins a la versió 2.0
A continuació és presenten les accions bàsiques a realitzar per accedir a bases de dades des de java.
El primer que cal fer és establir una connexió amb el controlador de base de dades que vulguem fer
servir. Això implica dues pases: (1) carregar el driver i (2) fer la connexió pròpiament dita.
try
{ class.forName("org.postgresql.Driver");
}
catch(ClassNotFoundException ex)
{ //Codi de l'excepció
}
El mètode forname carrega el controlador que correspon a la cadena que passem per paràmetres.
En aquest cas estaríem carregant el controlador del SGBD postgresql.
Pàgina 79 de 87
Curs Programació Java nivell bàsic.
Els noms del controladors de diferents SGBD els podeu trobar en el següent enllaç
http://www.newfire.com/newfire/html/doc/config/driver.html
Així doncs pel cas d’Oracle caldria fer:
try
{ class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException ex)
{ //Codi de l'excepció
}
La documentació del fabricant del driver ens dirà exactament quina url posar. Concretament en el cas
d’Oracle caldria fer quelcom com:
Ara què disposem de l’objecte Connection podem utilitzar comandes SQL. JDBC ens proporciona tres
tipus d’objecte per aconseguir aquest propòsit.
Statement: Ens permet fer una consulta o manipulació de dades (SELECT, CREATE o UPDATE).
PreparedStatement: Ens permet precompilar la comanda per a oferir millors prestacions.
CallableStatement: Ens permet cridar a procediments definits en la BD.
Per a obtenir aquests objectes ho farem des de l’objecte del tipus Connection
// Statement
Statement stmt = connexio.createStatement();
// PreparedStatement
PreparedStatement preStmt = connexio.prepareStatement("UPDATE TAULA1 SET
CAMP1 = ? WHERE ID = ?");
// CallableStatement
CallableStatement callStmt = con.prepareCall("{call nom_procediment}");
Pàgina 80 de 87
Curs Programació Java nivell bàsic.
1. executeQuery. Rep com a paràmetre la query, atenció query, que volem executar i retorna un
objecte ResultSet per poder accedir-hi a les dades.
ResultsetSet rs = stmt.executeQuery("SELECT * FROM TAULA");
2. executeUpdate. Rep com a paràmetre una sentència SQL de modificació de dades, és a dir, un
create, insert, delete, update.
int nombreFilesAfectades = stmt.executeUpdate("DELETE FROM
TAULA1 WHERE id like 'id-100%');
Encara que els objectes PreparedStatement es poden fer servir amb sentències SQL sense
paràmetres, és molt més freqüent fer-les servir amb sentències amb paràmetres.
En aquest cas el mètode que ens proporciona el PreparedStatement té un paràmetre que és la comanda
SQL. Aquesta comanda es enviada al controlador de la BD i precompilada. Ara hem assignar valor a
aquells llocs on hem situat el caràcter ?. Per fer-ho utilitzarem els mètodes que té el PreparedStatement
per aquesta finalitat. Són del tipus setXXX(valor).
preStmt.setInt(1, 12);
preStmt.setString(2, "id-1000");
Una vegada que a un paràmetre se li ha assignat un valor, el valor permaneix fins que s’estableixi un
altre valor diferent o fins que es cridi al mètode clearParameters.
while (resultSet.next())
{ System.out.println("El id és: "+ resultSet.getString("ID"));
System.out.println("camp1 és: "+ resultSet.getInt("CAMP1"));
System.out.println("camp2 és: "+ resultSet.getString("CAMP2");
}
Pàgina 81 de 87
Curs Programació Java nivell bàsic.
El mètode next() accedeix una a una a les fileres que contenen les dades.
Els mètodes getXXX("nom columna") ens retornen el valor de la columna especificada per paràmetre en
la fila actual.
5.1.6 Transaccions
Hi ha vegades que no volem que una sentència tingui efecte a menys que altre hagi acabat bé.
Un exemple típic és una transferència entre dos comptes bancaris, on no voldrem restar la
quantitat de la compta d’origen a menys que s’hagi sumat bé la quantitat traspassada al compte
de destí. Una transacció és un conjunt d’una o més sentències que s’executen como una unitat, és a dir,
o s’executen totes o ninguna.
con.setAutoCommit(false);
PreparedStatement updateSales = con.prepareStatement(
"UPDATE COFFEES SET SALES = ? WHERE COF_NAME
LIKE ?");
updateSales.setInt(1, 50);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
PreparedStatement updateTotal = con.prepareStatement(
"UPDATE COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE
?");
updateTotal.setInt(1, 50);
updateTotal.setString(2, "Colombian");
updateTotal.executeUpdate();
con.commit();
con.setAutoCommit(true);
Pàgina 82 de 87
Curs Programació Java nivell bàsic.
La línea final de l’exemple anterior activa el mode auto-commit, el que significa que cada sentència serà
novament entregada automàticament. És a dir, tornem a l’estat per defecte, en el qual no tenim que
cridar al mètode commit. És una bona pràctica desactivar el mode auto-commit només mentre vulguem
estar en mode transacció. D’aquesta forma, evitarem bloquejar la base de dades durant vàries
sentències, fet que incrementa la possibilitat de conflictes amb altres usuaris.
El següent exemple mostra, a més a més, una estructuració en classes que implementa, de forma lliure i
simplificada, el patrons de disseny DAO (Data Access Object) i el DTO (Data Transfer Object).
Podeu trobar informació detallada d’aquest dos patrons a:
http://www.programacion.com/java/tutorial/patrones2/8/
http://www.programacion.com/java/tutorial/patrones2/4/
Pàgina 83 de 87
Curs Programació Java nivell bàsic.
}
return((GrupGiga[])res.toArray(new GrupGiga[res.size()]));
}
package ub.ges.util.bd;
//SQL
import ...
/**
* Executa com una única transacció totes les accions
* de base de dades rebudes com a paràmetre. Fa log dels
* errors.
* @param String[] accions a realitzar a la BD.
*
*/
public void executarTransaccio(ArrayList accions) throws SQLException
{ Connection con=null; Statement stmt = null;
// Establir la connexió
try
{ con = ds.getConnection(); stmt = con.createStatement(); con.setAutoCommit(false);
}
catch(SQLException sqlEx)
{ tancarConStmt(con, stmt);
throw sqlEx;
}
Pàgina 84 de 87
Curs Programació Java nivell bàsic.
/**
* Retorna el seguent valor d'un sequenciador
* @param long
*
*/
public long seguentValSeq(String seq) throws SQLException
{ Connection con=null; Statement stmt = null; ResultSet rs = null;
String query; long seguent;
// Establir la connexió
try
{ con = ds.getConnection(); stmt = con.createStatement();
}
catch(SQLException sqlEx)
{ tancarConStmt(con, stmt);
throw sqlEx;
}
/**
* Tanca la connexió i el statement. Si peta, fa log de
* l'excepció, però no la llença cap a dalt, per tal de
* no perdre la possible excepció de la acció real sobre
* la BD
*/
public void tancarConStmt(Connection con, Statement stmt)
{ try
{ if (stmt != null) stmt.close();
if (con != null && !con.isClosed()) {con.close();}
}
catch(SQLException sqlEx)
{ logger.error("Excepció tancant conexió:",sqlEx);
Pàgina 85 de 87
Curs Programació Java nivell bàsic.
}
}
}
• Anar endavant i també endarrere en un full de resultats (resultSet) i fins i tot moure’ns
fins a una fila específica.
• Fer actualitzacions de les taules de la base de dades fent servir mètodes Java en lloc de
fer servir comandes SQL.
• Enviar múltiples sentències SQL a la base de dades com a una unitat, o batch.
• Accedir a nous tipus de dades SQL99 com valors de columnes, com són BLOB i CLOB
• Pool de connexions.
• Transactional Savepoints. Permet establir marques dintre d’una transacció, per permetre
desfer (rollback) no tota la transacció sencera sinó només fins a un marca (savepoint)
determinat.
• Control més fi del pool de connexions. Permet definir un màxim, mínim, el número
inicial, temps d’inactivitat d’una connexió abans de ser estreta del pool ... Fins i tot fer
cache de statements.
• Recuperació automàtica de les “keys autogenerades”. Serveix tan per obtenir el rowId
resultant d’un insert, com una primary key generada mitjançant seqüences.
• Possibilitat d’actualització, no només de lectura, de BLOB i CLOB (long binary data).
5.4 Exercicis
Pàgina 86 de 87
Curs Programació Java nivell bàsic.
Li afegim un mètode Persona getPersonaByDNI(String DNI) que retorni la persona amb el DNI rebut com
a paràmetre.
Pàgina 87 de 87