You are on page 1of 87

Curs Programació Java nivell bàsic.

Curs Java nivell bàsic.

Creat per Julio Peñuela Gil


Email: jpenuela@ub.edu
Versió 1.1
Març 2007

Pàgina 1 de 87
Curs Programació Java nivell bàsic.

1 INTRODUCCIÓ A JAVA I AL JDK................................................................................................................. 4


1.1 QUÈ ÉS JAVA?.................................................................................................................................................. 4
1.2 CARACTERÍSTIQUES DE JAVA .......................................................................................................................... 4
1.3 API’S DE JAVA ................................................................................................................................................ 5
1.4 LA MÀQUINA VIRTUAL..................................................................................................................................... 6
1.5 EL JDK ........................................................................................................................................................... 6
1.5.1 Comandes disponibles ............................................................................................................................. 7
1.5.1.1 Comandes imprescindibles: javac, java .............................................................................................................7
1.5.1.2 Comandes auxiliars: javadoc, jar .......................................................................................................................7
1.5.2 Ajuda en JDK .......................................................................................................................................... 9
1.5.3 Exercici 1.1.............................................................................................................................................. 9
1.5.4 Exercici 1.2............................................................................................................................................ 10
2 JAVA, EL LLENGUATGE NO OO ................................................................................................................ 12
2.1 INTRODUCCIÓ. ............................................................................................................................................... 12
2.2 ELEMENTS BÀSICS ......................................................................................................................................... 12
2.2.1 Comentaris ............................................................................................................................................ 12
2.2.2 Sentències .............................................................................................................................................. 14
2.2.3 Blocs de codi.......................................................................................................................................... 14
2.2.4 Paraules reservades .............................................................................................................................. 14
2.3 TIPUS DE DADES ............................................................................................................................................ 15
2.3.1 Tipus de dades simples: tipus numèrics................................................................................................. 15
2.3.2 Tipus de dades simples: booleans, caràcters i cadena. ......................................................................... 16
2.3.3 Matrius .................................................................................................................................................. 17
2.4 EXPRESSIONS I CONTROL DE FLUX ................................................................................................................. 18
2.4.1 Identificadors......................................................................................................................................... 18
2.4.2 Literals................................................................................................................................................... 19
2.4.3 Expressions............................................................................................................................................ 20
2.4.3.1 Expressions amb objectes ................................................................................................................................20
2.4.4 Operadors.............................................................................................................................................. 21
2.4.4.1 Operadors aritmètics........................................................................................................................................21
2.4.4.2 Operadors lògics ..............................................................................................................................................22
2.4.4.3 Operadors d'assignació ....................................................................................................................................22
2.4.4.4 Operadors a nivell de bit..................................................................................................................................23
2.4.4.5 Operador de conversió.....................................................................................................................................23
2.4.5 Sentències de control de flux ................................................................................................................. 23
2.4.5.1 Sentències condicionals ...................................................................................................................................24
2.4.5.2 Sentències de bucle..........................................................................................................................................25
2.4.5.3 Sentències d'alteració del flux..........................................................................................................................26
2.5 ESTRUCTURA DE FITXERS FONT ..................................................................................................................... 27
2.5.1 Declaració de classes ............................................................................................................................ 27
2.5.2 Declaració de mètodes de la classe....................................................................................................... 28
2.5.2.1 El mètode inicialitzador...................................................................................................................................28
2.5.3 Declaració de variables......................................................................................................................... 29
2.5.4 Regles d'àmbit en Java .......................................................................................................................... 29
2.6 PRIMERS PROGRAMES EN JAVA ...................................................................................................................... 31
2.6.1 Exemple: suma de dos nombres............................................................................................................. 31
2.6.2 Exercicis ................................................................................................................................................ 31
2.6.2.1 Exercici 2.1......................................................................................................................................................31
2.6.2.2 Exercici 2.2......................................................................................................................................................31
2.6.2.3 Exercici 2.3......................................................................................................................................................32
2.6.2.4 Exercici 2.4......................................................................................................................................................32
2.6.2.5 Exercici 2.5......................................................................................................................................................32
2.6.2.6 Exercici 2.6......................................................................................................................................................32
3 JAVA, EL LLENGUATGE OO ....................................................................................................................... 33
3.1 OBJECTES I CLASSES ...................................................................................................................................... 33
3.1.1 Declaració d'una classe......................................................................................................................... 33
3.1.1.1 Exercici 3.1......................................................................................................................................................33
3.1.2 Modificadors.......................................................................................................................................... 35

Pàgina 2 de 87
Curs Programació Java nivell bàsic.

3.1.2.1 Modificadors d’emmagatzemament i temps d’existència ................................................................................35


3.1.2.2 Modificadors d'accés .......................................................................................................................................36
3.1.2.3 Resum dels permisos d’accés ..........................................................................................................................36
3.1.3 Utilitzar objectes ................................................................................................................................... 39
3.1.3.1 Exercici 3.2......................................................................................................................................................39
3.1.3.2 Exercici 3.3......................................................................................................................................................39
3.1.4 Comparació d'objectes en Java ............................................................................................................. 40
3.1.5 Còpia d'objectes en Java ....................................................................................................................... 41
3.1.6 Els objectes més usats en Java .............................................................................................................. 42
3.1.6.1 La classe String................................................................................................................................................42
3.1.6.2 Els wrappers ....................................................................................................................................................43
3.1.7 Conversions entre strings i els tipus bàsics ........................................................................................... 44
3.1.7.1 Exercici 3.4......................................................................................................................................................46
3.1.8 Matrius d'objectes.................................................................................................................................. 46
3.1.8.1 Exercici 3.5......................................................................................................................................................46
3.2 HERÈNCIA ..................................................................................................................................................... 47
3.2.1 Herència simple en Java........................................................................................................................ 47
3.2.1.1 Exemple d' herència simple: la superclasse .....................................................................................................48
3.2.1.2 Exemple d' herència simple: la subclasse ........................................................................................................49
3.2.1.3 Classes i mètodes abstractes ............................................................................................................................50
3.2.1.4 Exercici 3.6......................................................................................................................................................50
3.2.1.5 Exercici 3.7......................................................................................................................................................51
3.2.1.6 Exercici 3.8......................................................................................................................................................51
3.2.1.7 Exercici 3.9......................................................................................................................................................52
3.2.2 Interfaces ............................................................................................................................................... 54
3.2.3 Herència múltiple en Java ..................................................................................................................... 55
3.2.3.1 Exemple d’herència múltiple: la superclasse i la interfície ..............................................................................55
3.2.3.2 Exemple d'herència múltiple: la subclasse.......................................................................................................56
3.3 EXCEPCIONS .................................................................................................................................................. 58
3.3.1.1 Exercici 3.10....................................................................................................................................................62
3.3.1.2 Exercici 3.11....................................................................................................................................................62
3.4 PACKAGES ..................................................................................................................................................... 63
3.4.1 Ús de packages ...................................................................................................................................... 63
3.4.2 Com col·loca el compilador els packages ............................................................................................. 64
3.4.3 Àmbit del package ................................................................................................................................. 64
3.4.4 Exercici 3.12.......................................................................................................................................... 64
4 CLASSES D’UTILITAT. .................................................................................................................................. 66
4.1 TREBALLAR AMB DATES I HORES................................................................................................................... 66
4.1.1 Classe Date............................................................................................................................................ 66
4.1.2 Classes Calendar i Gregorian Calendar ............................................................................................... 66
4.1.2.1 Leniency ..........................................................................................................................................................67
4.1.3 Exercicis ................................................................................................................................................ 68
4.1.3.1 Exercici 4.1......................................................................................................................................................68
4.1.3.2 Exercici 4.2......................................................................................................................................................68
4.1.3.3 Exercici 4.3......................................................................................................................................................68
4.1.3.4 Exercici 4.4......................................................................................................................................................69
4.1.4 Classes DateFormat i SimpleDateFormat............................................................................................. 69
4.1.4.1 Exercici 4.5c ....................................................................................................................................................70
4.1.4.2 Exercici 4.5......................................................................................................................................................70
4.2 JCF: JAVA COLLECTIONS FRAMEWORK ......................................................................................................... 71
4.2.1 Introducció ............................................................................................................................................ 71
4.2.2 Interfaces e Implementacions ................................................................................................................ 71
4.2.2.1 Collection ........................................................................................................................................................71
4.2.2.2 Set....................................................................................................................................................................73
4.2.2.3 Exercici 4.7......................................................................................................................................................74
4.2.2.4 List...................................................................................................................................................................74
4.2.2.5 Exercici 4.8......................................................................................................................................................74
4.2.2.6 Queue...............................................................................................................................................................75
4.2.2.7 Map..................................................................................................................................................................75
4.2.3 Algoritmes. Ordenacions. ..................................................................................................................... 76
4.2.4 Exercici 4.9............................................................................................................................................ 78
4.2.5 Exercici 4.10.......................................................................................................................................... 78
5 JDBC................................................................................................................................................................... 79

Pàgina 3 de 87
Curs Programació Java nivell bàsic.

5.1 JDBC 1.0....................................................................................................................................................... 79


5.1.1 Establiment de la connexió.................................................................................................................... 79
5.1.1.1 Carregar el Driver............................................................................................................................................79
5.1.1.2 Fer la Connexió. ..............................................................................................................................................80
5.1.2 Obtenció de l’objecte necessari per executar sentències SQL............................................................... 80
5.1.3 Execució de la sentències SQL. ............................................................................................................. 81
5.1.4 Obtenció dels resultats de les consultes SQL ........................................................................................ 81
5.1.5 Tancant objectes .................................................................................................................................... 82
5.1.6 Transaccions.......................................................................................................................................... 82
5.1.6.1 Desactivar el mode “Auto-entrega” .................................................................................................................82
5.1.6.2 Entregar una Transacció ..................................................................................................................................82
5.1.6.3 Quan cridar al mètode rollback........................................................................................................................83
5.1.7 Exemple sencer d’accés a base de dades............................................................................................... 83
5.2 JDBC 2.0....................................................................................................................................................... 86
5.3 JDBC 3.0....................................................................................................................................................... 86
5.4 EXERCICIS ..................................................................................................................................................... 86
5.4.1 Exercici 5.1............................................................................................................................................ 86
5.4.2 Exercici 5.2............................................................................................................................................ 87

1 Introducció a Java i al JDK.

1.1 Què és Java?


Java es remunta fins al 1991, quan un grup d’enginyers de Sun Microsystems es proposaren de
dissenyar un petit llenguatge que pogués ser utilitzat en el control de dispositius de consum com aparells
de TV, vídeos, telèfons mòbils, rentadores, forns microones, etc. La idea era crear una màquina, la Java
Virtual Machine, de la qual aquests electrodomèstics podien integrar-ne la part que necessitessin.

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.

La URL de referència del món Java és:

http://java.sun.com/
Trobareu gran quantitat de documentació, manuals i notícies relatives, en castellà, a www.javahispano.org

També interessant la url www.programacion.com/java

Multitud d’exemples a http://javaalmanac.com/

1.2 Característiques de Java


• Simple.- Java és fàcil i entenedor. Un altre aspecte de la seva simplicitat és que és petit. Un dels
objectius de Java és permetre la construcció de programari que es pugui executar en màquines
petites.

• 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.

• Arquitectura multiplataforma.- El compilador genera un format de fitxer de programa objecte


d'una arquitectura neutra, és a dir, el codi del compilador s'executa en molts processadors atesa
la presència d'un sistema interpretador en temps d'execució de Java. El compilador de Java
genera instruccions de codi byte (bytecode) que no tenen res a veure amb una arquitectura de
cap sistema en particular. Més aviat, s'ha dissenyat per ser fàcil d'interpretar en qualsevol
màquina i fàcil de traduir en el codi de la màquina nadiua.

• Portable.- A diferència de C i de C++, no hi ha una implementació dependent dels aspectes de


l'especificació. S'especifiquen les mides dels tipus de dades primitius i el comportament de
l'aritmètica d'aquestes dades. Les llibreries que formen part del sistema defineixen interfícies
portables.

• 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

1.3 API’s de Java


Java incorpora un conjunt d’API que permet ampliar les funcionalitats ofertes al programador per tal de
crear aplicacions.

• 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.

1.4 La màquina virtual


El punt més important de Java és el fet de poder ser executat en qualsevol plataforma. Aquesta
independència, tant de sistema operatiu com d’arquitectura física, s’aconsegueix amb un sistema
intermedi: la Màquina Virtual de Java.

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 (Just-In-Time o JIT)

• els compiladors nadius.

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.

Micro Edition: J2ME. Dirigida a dispositius portàtils (PDA’s, mòbils ...)

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.

1.5.1 Comandes disponibles


El JDK ofereix un conjunt d'eines per tal d'ajudar al desenvolupador. Tot i que l’ús dels IDE’s actuals fa
gairebé innecessari el seu ús manualment des de línea de comandes, no està de més tenir una idea
bàsica del seu funcionament.

1.5.1.1 Comandes imprescindibles: javac, java


• javac. Compilador de codi Java. Converteix el codi dels arxius font .java a codi byte.
javac [ opcions ] nomfitxer1.java [nom2.java...]
Algunes opcions disponibles són :
-classpath path: permet especificar el directori on es van a buscar les classes necessàries per
a executar javac i altres classes referenciades per les classes que compilem.
-d directory: permet especificar el directori arrel de la jerarquia de classes i hi deixa els fitxers
compilats.
-deprecation: genera un avís quan utilitzem una classe o membre desaprovat (deprecated).
-nowarn: desactiva els avisos (warnings).
-O: aplica optimització independent de la plataforma.
-verbose: mostra missatges sobre els fitxers que es compilen i els que es carreguen.
-depend: recompila les classes de les quals depenen el nostre codi.

• 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.

1.5.1.2 Comandes auxiliars: javadoc, jar


• javadoc. Generador de documentació. Genera a partir del codi font d'un programa una
documentació de totes les classes que la composen, creant un arxiu de text, normalment en

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.

1.5.2 Ajuda en JDK


Com ja s'ha dit abans, una de les complexitats de Java és el conèixer la gran quantitat de classes que ja
porta implementades el JDK. Quan programem en Java, si no volem escriure codi que ja es troba fet a
les llibreries de Java, hem de tenir algun tipus de manual de referència del llenguatge.

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.

• L'àrea de descripcions, a la part centre-dreta de la pantalla, on es pot veure la descripció d’allò


que hem escollit a les àrees esquerres.
Per exemple, si volem obtenir informació sobre la classe Date (una classe que permet representar dates
-dia i hora- en Java):
1. podem escollir a l'àrea superior esquerra l'opció "All Classes" o bé el paquet "java.util".

2. busquem a la llista de classes la classe Date i l'escollim

3. mirem la descripció de la classe a l'àrea centre-dreta.

1.5.3 Exercici 1.1

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
{

public static void main(String[] args)


{ System.out.println ("Hello World");
metode1("a");
}

public static int metode1 (String p1)


{ System.out.println (p1);
return 24;
}

2. Determinar amb quina versió de JDK estem treballant.

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).

4. Generar la documentació JavaDoc mitjançant l’eina del JDK.

5. Ara crearem un projecte amb el Jdeveloper, que sigui el mateix HelloWord, el compilarem,
l’executarem i el documentarem.

1.5.4 Exercici 1.2

La següent aplicació Java no està ben programada.

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:

java IgualtatStrings hola adeu

L’aplicació diu que són diferents.

I si l'usuari escriu el següent:

java IgualtatStrings hola hola

L'aplicació també diu que són diferents, quan hauria de dir que són iguals.

L'error al codi anterior es troba en la comparació de cadena1 i cadena2, variables de la classe


String.

En aquest exercici heu de:

• 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++.

Els objectius principals d’aquest mòdul són:

1. Conèixer la sintaxi de Java.

2. Conèixer els tipus de dades bàsics de Java.

3. Aprendre l’estructura dels fitxers font de Java

4. Familiaritzar-nos amb el IDE Jdeveloper 10g

2.2 Elements bàsics


En aquest tema veurem els elements bàsics que composen la gramàtica de Java. En concret, veurem:

• Comentaris. El programador n'inserta per a la documentació.

• Sentències. Línies de programa

• Bloc de codi. Grup de sentències que formen una unitat.

• 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:

/*això és un comentari Java*/

/*aquest és un altre comentari


que té dues línies*/

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:

/**això és un comentari Java que servirà per a javadoc*/

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.

//Aquest comentari només pot ocupar una línia


//Aquesta és la segona línia del comentari

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;

és la mateixa línea de codi que

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.

2.2.3 Blocs de codi


Les sentències es poden agrupar en blocs per tal que una sola pugui controlar de manera senzilla
l'execució de moltes altres. Els blocs de codi Java estan delimitats per claus ('{' i '}').
Els blocs de codi es poden imbricar dins d'altres blocs de codi.

Per exemple, un bloc de codi podria ser:

{
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:

2.2.4 Paraules reservades


Una paraula reservada és una paraula que té un significat especial per al compilador de Java i que no
podem utilitzar nosaltres per a donar nom a les nostres funcions, variables, tipus de dades, objectes, etc.
La llista de paraules reservades és:

abstract boolean break byte

case catch charr class

const* continue default do

double else extends final

finally float fot Goto*

if implements import instanceof

int interface long native

new null package private

Pàgina 14 de 87
Curs Programació Java nivell bàsic.

protected public return short

static super switch syncronized

this throw throws transient*

try void volatile while

* aquestes paraules reservades no s'utilitzen actualment.

2.3 Tipus de dades


Els tipus de dades simples es troben integrats en el nucli de Java i no hi ha cap necessitat de fer
referència a cap llibreria del nucli. Aquests tipus poden classificar-se en:

• numèrics: byte, int, long, short, float, double.

• booleans: boolean.

• caràcters: byte, char.


Java també té tipus de dades complexos en què cal fer referència a les llibreries del nucli API. Aquest
tipus de dades són:
• els objectes (que poden ser del nucli o definits per l'usuari), i que veurem en el següent mòdul.

• 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.

2.3.1 Tipus de dades simples: tipus numèrics


Java té sis tipus de dades numèrics que es diferencien en mida i precisió dels nombres que pot contenir.
Els tipus de dades numèrics són:

Tipus Descripció Mida Valors mínim i màxim

byte enter amb signe de mida molt petita 8 bits Mín: -128

Màx: 127

short enter curt amb signe 16 bits Mín: -32768

Màx: 32767

int Enter amb signe 32 bits Mín: -2147483648

Màx: 214748364

long Enter llarg amb signe 64 bits Mín: -9223372036854775808

Màx: 9223372036854775808

Pàgina 15 de 87
Curs Programació Java nivell bàsic.

float Nombre amb coma flotant 32 bits Mín:


Positiu:
1.40239846e-45
Negatiu:
-3.40282347e38

Màx:
Positiu:
3.40282347e38
Negatiu:
-1.40239846e-45

double Nombre amb coma flotant 64 bits Mín:


Positiu:
4.94065645841246544e-324
Negatiu:
-1.79769313486231570e308

Màx:
Positiu:
1.79769313486231570e308
Negatiu:
-4.94065645841246544e-324

2.3.2 Tipus de dades simples: booleans, caràcters i cadena.


Tipus de dades booleans
Les variables de tipus booleà tenen valor true (cert) o false (fals). La majoria dels llenguatges tracten els
enters com a variables lògiques i consideren el zero false i qualsevol altre valor true. Malgrat tot, com en
Pascal, Java té el seu propi tipus booleà, diferent de qualsevol tipus numèric. Les variables booleanes no
inicialitzades s'inicien com a false.

Tipus de dades de caràcter


El tipus de dades de caràcter, char, conté un sol caràcter. Cada caràcter és un nombre o codi de caràcter
que es refereix a un joc de caràcters que és una llista indexada de símbols.
El tipus char de Java és de 16 bits i conté un codi Unicode més que un codi ASCII. Unicode és una
versió ampliada del joc de caràcters ASCII, dissenyat amb molts idiomes.

Tipus de dades de cadena


Una cadena (string) és una seqüència de caràcters. El tipus de dades de cadena és en realitat una
classe del nucli API (java.lang.String), més que no pas un tipus integrat, per la qual cosa les
cadenes de caràcters són objectes.
Les cadenes poden ser tan llargues com es vulgui encara que la majoria de les implementacions la
limitaran probablement al voltant de dos bilions de caràcters. Aquesta capacitat és més que suficient per
a gairebé qualsevol aplicació.

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).

figura 2.1: Exemple de matriu de nombres i de matriu de cadenes

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.

Declaració d'una matriu


Per a declarar una matriu (array) es fan servir els claudàtors ('[' i ']'). Hi ha dues maneres de declarar
una matriu: una consisteix a col·locar els claudàtors darrere del nom del tipus de dades i l’altra és
col·locar-los darrere del nom de la matriu. Llavors serien equivalents aquestes dues declaracions:

int[] un_array = new int[3];

int un_array[] = new int[3];

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:

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

El resultat d'aquesta declaració és el següent:

figura 2.2: Una matriu multidimensional no rectangular.

Còpia d'una matriu


Com que una matriu és un objecte, l'assignació del valor d'una variable array a una altra...

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);

2.4 Expressions i control de flux


Hem vist en temes anteriors el que eren les sentències i els blocs de codi. També hem vist un primer
tipus de sentència: les declaracions de variables.

En aquest tema veurem altres tipus de sentències, en concret:

• les expressions

• les sentències de control de flux.


Abans parlarem d'altres conceptes relacionats amb les sentències: els identificadors de les variables i
els literals.

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.

No hi ha límit en el nombre de caràcters. Els identificadors no estan restringits a caràcters ASCII. Si


l’editor ho permet, es poden utilitzar caràcters Unicode en els noms de variables.

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:

Dígits decimals (que no comencin per 0)


Byte,
0x seguit de dígits hexadecimals; per exemple, 0xFF12
short, int
0 seguit de dígits octals, per exemple 0726
Igual que el tipus int, però seguit del caràcter I o L; per exemple, 1234L,
Long
0x12FABL, 0345345L, 11234I
Dígits amb un punt decimal i/o exponent, seguits del caràcter f o F; per
Float
exemple, 1.234f, 1.234E+5F
Igual que el tipus float, però sense el sufix f o F i amb el sufix opcional D;
double
per exemple, 1.234D, 1.234, 1.234E+5
boolean true o false
Qualsevol caràcter ASCII entre apòstrofs; per exemple 'a' o 'B'. Si l'editor
permet caràcters Unicode també poden anar entre cometes simples.
char
Una seqüència d'escapament predefinida entre apòstrofs; per exemple, '\t',
'\012'
Seqüència de caràcters o seqüències d'escapament entre cometes, per
String
exemple, "Hola món\n"

A la sentència següent:

comptador = 325;

325 és un literal del tipus int.

A la sentència següent:

nom = “Julio”;

Julio és un literal del tipus String.

La sentència següent:

nom = ‘Julio’;

donarà un error de compilació.

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;

En aquest segon cas, tant a com b, tindran valor 15.

Expressions amb operadors

La resta de tipus d’expressions contenen combinacions de variables, literals, crides a funcions i


operadors.

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).

2.4.3.1 Expressions amb objectes


Per completesa, introduirem aquí les expressions que involucren objectes, encara que veurem el detall
de com treballar amb objectes al següent mòdul.

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);

En el cas de variables estàtiques i funcions estàtiques, les crides serien:

classe.variable
classe.funció(arguments);

Crear instàncies d'objectes

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:

new nomClasse (arguments);

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.

Vegem a continuació els diferents tipus d'operadors:

• Operadors aritmètics

• Operadors lògics

• Operadors d'assignació

• Operadors a nivell de bit

• 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...

En Java el programador no pot sobrecarregar encara més els operadors

És a dir, no pot afegir més "usos" o "significats" dels que ja té un operador.

2.4.4.1 Operadors aritmètics


Són els operadors que permeten sumar, restar, multiplicar, dividir i fer el canvi de signe.

Operador Propòsit Preferència Associativitat

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

2.4.4.2 Operadors lògics


Són els operadors de les expressions booleanes. Permeten comparar magnituts i combinar
subexpressions booleanes.

Operador Propòsit Preferència Associativitat

<,>,<=,>= Verifica magnituds 7 Esquerra

== Verifica la igualtat 8 Esquerra

!= Verifica la desigualtat 8 Esquerra

Condicional; retorna un
?: dels dos operands en 14 Dreta
funció d'un tercer

! Negació 2 Dreta

&& AND Condicional 12 Esquerra

|| OR Condicional 13 Esquerra

2.4.4.3 Operadors d'assignació


L'operador d'assignació assigna el segon operador al primer i retorna el segon operador com a resultat
de l'assignació.
Exemple:

int i;
i = i + 5;

//també es pot usar

int i;
i += 5;

Pàgina 22 de 87
Curs Programació Java nivell bàsic.

Hi ha, doncs, tres operadors d'assignació: = , += i -=

É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.

2.4.4.4 Operadors a nivell de bit


Són operadors que treballen amb les representacions en bits dels valors. No els veurem en aquest curs.

2.4.4.5 Operador de conversió


L'operador de conversió (o casting) serveix per a convertir un tipus de dades en un altre.

Per a realitzar la conversió, s’escriu el nom del tipus a què es vol convertir entre parèntesi.
Exemple:

int i;
long l;

l = 100000000; //l és un nombre molt gran


l = l / 10000;
i = (int) l;//l es converteix a enter

2.4.5 Sentències de control de flux


Normalment el conjunt de sentències d'un bloc de codi s'executen un únic cop, des de la primera fins la
última

{
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

• Sentencies d’alteració del flux.

2.4.5.1 Sentències condicionals


Aquestes sentències permeten l'execució selectiva de parts de programa d'acord amb el valor d'algunes
expressions. Java inclou dos tipus de sentències condicionals: if i switch.

Sentències if

La forma general d'una sentència if és:

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;
...

En aquest cas, si i val 1, el valor d'a serà 1, si no, serà 2.

Sentències switch

La forma general d'una sentència switch és:

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.

case 2: valor_segon = 2;break;


default: break;
}

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.

2.4.5.2 Sentències de bucle


Les sentències de bucle permeten l'execució repetida de blocs de sentències. Hi ha tres tipus de
sentències de bucle: for, while i do. Les sentències for i while avaluen la condició al
començament del bucle, mentre que do ho fa al final, quan ja s'ha executat.

Sentències for

La forma general d'una sentència for és:

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:

int v[] = {3,5,43,23,2};


for (int valor:v )
{ System.out.println(valor);
}

Sentències while

La forma general d'una sentència while és:

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

La forma general d'una sentència do-while és:

do
<cos_bucle>
while (<expressió_condicional>)
Per exemple:
do
{
i= i+1;
}while (i<final)

2.4.5.3 Sentències d'alteració del flux


Java inclou tres tipus de sentències d'alteració del flux. Aquestes sentències s’utilitzen per a sortir de
sentències switch, bucles i blocs etiquetats. Les sentències continue s'utilitzen per a bifurcar al final
d'un bucle just després de l’ultima línia de sentències. Les sentències return s'utilitzen per a sortir d'un
mètode. Les sentències o blocs de sentències delimitades entre claus poden etiquetar-se per fer-ne
referència posteriorment en les sentències break.

Sentències break

La forma general d'una sentència break és:

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

La forma general d'una sentència continue és:

continue [<etiqueta>];
etiqueta és opcional i actua de la mateixa manera que en la sentència break.

Sentències return

La forma general d'una sentència return és:

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.

2.5 Estructura de fitxers font


Després de veure cadascuna de les peces bàsiques que formen la sintaxi de Java, vegem com juntar-les
per a formar programes, és a dir, vegem com crear un fitxer font.

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.

Les sentències package, import i class han de constar en aquest ordre.

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.

2.5.1 Declaració de classes


La declaració d'una classe comença per la paraula reservada class seguida del nom de la classe.

modificador(s) class <nom_de_la_classe>


{
declaració_variables
declaració_funcions
[inicialitzador_de_la_classe]
}

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:

modificador(s) especificador_tipus identificador = valor_inicial;

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.

2.5.2 Declaració de mètodes de la classe


Les declaracions de les funcions o mètodes de la classe segueixen l'estructura següent:

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.

2.5.2.1 El mètode inicialitzador


L'inicialitzador de la classe és una funció o mètode especial que conté el codi que serà executat un sol
cop quan la màquina virtual (Virtual Machine VM) carregui la classe. Aquest inicialitzador depèn del tipus
de classe:

• 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.

2.5.3 Declaració de variables


Com ja s'ha avançat, abans de fer servir cap variable, cal declarar-la. La declaració d'una variable
especifica el tipus de dades, el nom de la variable i, opcionalment, el valor inicial de la variable. Una
declaració general de variable és:

tipus_dades identificador [= valor_inicial]


[, identificador [= valor_inicial]];

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.

Com a exemple de la declaració de variables en un mètode:

...
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;

return (total * iva);


}
...

2.5.4 Regles d'àmbit en Java


Les regles que dicten en quines parts del programa podem veure unes variables determinades
s'anomenen regles d'àmbit.

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.

La variable j definida en el mètode1es crea en declarar-la, després de la crida a la funció, i es destrueix


quan s'acaba la funció. El mateix passa amb la variable j del mètode2. Totes dues variables són
completament diferents.

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.

Les regles d'àmbit a les classes vénen donades pels modificadors:

• public implica que un mètode o atribut és visible des de qualsevol classe (àmbit global).

• private restringeix l'àmbit del mètode o atribut a la pròpia classe.

• 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.

2.6 Primers programes en Java


Ara que ja hem vist sencera la sintaxi de Java, apliquem el que hem vist en aquest mòdul creant
programes.

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.

2.6.1 Exemple: suma de dos nombres


Vegem ara un altre exemple, no gaire més complex que el HelloWorld, d'aplicació Java.

Fins ara havíem vist (a l'exemple del HelloWorld) com escriure missatges per pantalla, amb el mètode
System.out.println.

En aquest exemple veurem:

• Com comprovar que el nombre d'arguments amb què s'ha executat l'aplicació és el correcte.

• Com obtenir els arguments de la línia de comandes

• Com convertir una cadena (String) en un enter (int)

• Com construir una cadena per concatenació

Comentem el codi anterior:

• 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

2.6.2.1 Exercici 2.1


Fer els canvis necessaris a la classe Suma2nums per tal que es converteixi en SumaNnums, fent que
sumi tots els números rebuts com a paràmetre.

2.6.2.2 Exercici 2.2

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.

2.6.2.3 Exercici 2.3


Fer una variació de l’exercici anterior,anomenat MaxString, de forma que la taula sigui de Strings.

2.6.2.4 Exercici 2.4


Fer una variació dels exercicis anteriors, anomenat ExisteixInt de forma que el programa rebi com a
paràmetre un número i indiqui si aquest existeix o no a la que la taula que té definida com a un atribut
estàtic de la classe.

2.6.2.5 Exercici 2.5


Fer una clase java anomenda DiesMes que rebi en el seu mètode main un número representant el
número de mes (1 gener, 2 febrer, 3 març ...) i cridi a un mètode static i private anomenat
getDiesDelMes que rebi aquest número com a paràmetre i retorni el número de dies del més. Fer servir
el SWITCH.

2.6.2.6 Exercici 2.6


Refer algun dels exercicis anteriors fent servir el for-each en comptes del bucle for “tradicional”. Si tots
ells has fet amb el for-each, aleshores reescriu algun d’ells amb el for “tradicional”.

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.

3.1 Objectes i classes


Java és un llenguatge orientat a objectes pur. Aquests tipus de llenguatges només permeten que els
mòduls que formen un programa siguin classes. És a dir, Java és un llenguatge on tot es mou al voltant
del concepte de classe i de les seves instàncies, els objectes.

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.

3.1.1 Declaració d'una classe


La declaració d'una classe comença sempre per la paraula reservada class seguida del nom de la
classe. Opcionalment es poden afegir el nom de la superclasse (si l'objecte hereta d'una classe que no
sigui Object) i les interfícies que la classe implementi.

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.

3.1.1.1 Exercici 3.1

Fer en Java la declaració de la classe Vehicle:

• atributs:

o marca i model (cadenes de caràcters)

Pàgina 33 de 87
Curs Programació Java nivell bàsic.

o any de fabricació (enter)

o matrícula (cadena de caràcters)

o consum, en litres de carburant per cada 100 quilòmetres (float)

• mètodes:

o el constructor de la classe, que tindrà la capçalera següent:

Vehicle(String fabricant, String mod, int any, String prov_matr,


int num_matr, String lletres_matr, float consum)

on prov_matr és la o les lletres de la matrícula que formen el codi de província,


num_matr és el número de la matrícula i lletres_matr són les lletres adicionals que
solen portar les matrícules.

o per a cada atribut un mètode d'obtenció del seu valor.

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.

Els modificadors sempre precedeixen la declaració d'una classe, variable o mètode:

modificador(s) class <nom_de_la_classe>


{
...
}

modificador(s) tipus <nom_de_la_variable> = <valor_inicial>

modificador(s) tipus_del_resultat <nom_del_mètode> ( paràmetres )


{
...
}

A continuació veurem un a un els modificadors de Java.

3.1.2.1 Modificadors d’emmagatzemament i temps d’existència


abstract

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.

3.1.2.2 Modificadors d'accés


public

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.

Com a norma general, eviteu definir atributs i mètodes públics si no és necessari.

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.

3.1.2.3 Resum dels permisos d’accés


A continuació es presenta una taula resum dels permisos d’accés en Java:

Visibilitat Public Protected Private Default

Des de la pròpia classe Si Si Si Si

Des de una classe del Si Si No Si


mateix package

Des de altre classe d’altre Si No No No


package

Des de una subclasse del Si Si No Si


mateix package

Des de una subclasse Si No No Si


d’altre package

Pàgina 36 de 87
Curs Programació Java nivell bàsic.

Construir i inicialitzar objectes


Un dels mètodes de la classe és el mètode constructor, que permet instanciar objectes

En Java una classe pot tenir molts constructors diferents.

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;

Persona (int pdni)


{ num_dni = pdni;
}
Persona (int pdni, String pnom)
{ num_dni = pdni;
nom = pnom;
}

public int getDNI()


{ return (num_dni);
}
public String getNom()
{ return (nom);
}
public setNom(String pnom)
{ nom = pnom;
}
public String getAdreça()
{ return (adreça);
}
public setAdreça(String padreça)
{ adreça = padreç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.

3.1.3 Utilitzar objectes


Quan un objecte està creat, podem:

• Accedir als atributs visibles.

• Accedir als mètodes visibles.


Com ja hem explicat, els modificadors poden indicar la visibilitat o accessibilitat d'atributs i mètodes.
L’accés a un atribut es fa de la manera següent:

objecte.nom_atribut

essent objecte una variable que fa referència a un objecte.

L’accés a un mètode es fa de la manera següent:

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")

3.1.3.1 Exercici 3.2

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.

L'exercici consta de dues parts:

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

3.1.3.2 Exercici 3.3

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.

L'exercici consta de dues parts:

1. realitzar la declaració de la classe Matricula. Aquesta classe té com a atributs el codi de


província, els números i les lletres addicionals. 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 la matrícula sencera amb el format "Codi-
Números-Lletres".

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.

3.1.4 Comparació d'objectes en Java


Si observem el codi següent:

...
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.

Per a arreglar l'exemple, hauríem d'afegir un nou mètode a la classe Persona:

public boolean equals (Persona altre_persona)


{ return (num_dni == altre_persona.getDNI());
}

Amb aquest mètode estem dient que dos objectes de la classe Persona són iguals si el número de DNI
és igual.

Ara ja podem arreglar el codi anterior:

...
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.

3.1.5 Còpia d'objectes en Java


Si observem el codi següent:

...

Persona p1 = new Persona(12345678);


Persona p2 = new Persona(01234567);
...
p2 = p1;
...

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.

Per a arreglar l'exemple, hauríem d'afegir un nou mètode a la classe DNI:

public Persona clone ()


{ return (new Persona(num_dni));
}

Amb aquest mètode el que fem es retornar un objecte nou de trinca amb el número de dni de l'objecte
original.

Ara ja podem arreglar el codi anterior:

...

Persona p1 = new Persona(12345678);


Persona p2 = new Persona(01234567);
...
p2 = p1.clone();
...

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.

3.1.6 Els objectes més usats en Java


A continuació veurem com s’usen alguns dels objectes més usats en Java.

En concret, veurem:

• La classe String

• Els wrappers (Short, Integer, Long, Float, Double)


També veurem com treballar amb vectors d'objectes.

3.1.6.1 La classe String


Una de les classes més utilitzades en Java és la classe java.lang.String. Aquesta classe permet
tenir cadenes de caràcters i treballar amb elles de manera molt còmoda.

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:

char charAt(int pos) retorna el caràcter que es troba a la posició pos.


La primera posició d'un string és la posició 0.

int compareTo(String altre_string) permet comparar un string amb un altre. Si el


resultat és 0, els dos són iguals, si és positiu
l'string va després de altre_string en ordre
lexicogràfic, i si és negatiu l'string va davant de
altre_string en ordre lexicogràfic

String concat(String altre_string) retorna la concatenació de l'string amb


altre_string. Recordeu que també es poden
contatenar strings amb l'operador +.

boolean equals(String altre_string): Diu si l'string i altre_string són iguals

boolean equalsIgnoreCase(String Diu si l'string i altre_string són iguals, sense


altre_string) distingir majúscules de minúscules.

int length() retorna el nombre de caràcters de l'string (espais


en blanc i caràcters especials inclosos

String replace(char caràcter_vell, retorna un string que resulta de la substitució en


caràcter_nou) l'string actual de totes les aparicions de
caràcter_vell per caràcter_nou

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

char[] toCharArray() permet obtenir una taula dels caràcters que


formen l'string, en l'ordre en què apareixen a
l'string. Aquesta taula té tantes posicions com
digui el mètode length

String toLowerCase() retorna un altre string on totes les lletres s'han


passat a minúscules

Pàgina 42 de 87
Curs Programació Java nivell bàsic.

String toUpperCase() retorna un altre string on totes les lletres s'han


passat a majúscules

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!".

3.1.6.2 Els wrappers


Hi ha vegades que no podem treballar amb els tipus bàsics que porta Java (int, float, boolean,...).
Per exemple, quan volem passar una variable de qualsevol tipus com a referència, hem de passar un
objecte (ja que Java no té punters de memòria). També hi ha estructures de Java que només poden
emmagatzemar objectes, com per exemple els Arrays i els HashMaps.

Els tipus bàsics de Java tenen uns tipus corresponents en forma d'objecte: són els wrappers:

Tipus bàsic Classes wrapper

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.

Float obj_b = new Float(3.14159);


...
b = obj_b.floatValue();

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();

3.1.7 Conversions entre strings i els tipus bàsics


Pas de qualsevol dels tipus bàsics a String

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:

• com a servei de classe (és a dir, la conversió la fa la classe, no un objecte):

int a = 100;
String str;
...
str = Integer.toString(a);

• com a servei d'instància (és a dir, la conversió la fan els objectes).

Integer obj_a = new Integer(100);


String str;
...
str = obj_a.toString();

Pas de String a qualsevol dels tipus bàsics

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:

• public static Nom_classe valueOf(String str): analitza l'string i crea un objecte


numèric (Integer, Float, ...)

String str = "100";


Integer obj_a;
...
obj_a = Integer.valueOf(str);

• public static nom_tipus_base parse<Nom_tipus_base>(String str): analitza


l'string i retorna un valor del tipus bàsic (int, byte, float, ...). Per exemple: parseInt,
parseByte, parseFloat, ....

String str = "100";


int a;
...

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.

En el cas dels booleans, els mètodes s’anomenen valueOf i getBoolean, respectivament.

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.

3.1.7.1 Exercici 3.4

Programar un classe anomenada UsaVehicle que:

• 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).

3.1.8 Matrius d'objectes


Ja vam veure com crear i inicialitzar vectors en Java:

int[] un_array = new int[3];

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:

Integer[] un_array = new Integer[3];

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:

un_array[0] = new Integer(12);


un_array[1] = new Integer(7);
un_array[2] = new Integer(9+5);

3.1.8.1 Exercici 3.5

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.

3.2.1 Herència simple en Java


En Java, el fet que una classe (la subclasse o classe "filla") hereta d'una altra classe (la superclasse o
classe "pare") també se li diu estendre.

Les subclasses estenen la definició de les superclasses.

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:

• els atributs nous que necessita la classe

• els mètodes nous

• modificacions en el codi dels mètodes que ha heretat del "pare"


Declarar atributs i mètodes nous es fa com ja hem vist a les classes que es defineixen des de zero.
Modificar el codi d'un mètode heretat escrivint-lo des de zero també és fàcil: hem de crear un mètode
que tingui el mateix nom i els mateixos paràmetres que en el pare. Normalment haurem d’escriure des de
zero el codi d'un mètode heretat quan es tracta d'un mètode abstracte (un mètode no implementat a la
classe pare).

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.

3.2.1.1 Exemple d' herència simple: la superclasse


Vegem un exemple d'herència simple. En aquest exemple definirem una classe NIF a partir d’una
classe DNI.

Primer de tot, definim la molt simple classe DNI:

class DNI
{ protected int num_dni;
DNI (int xifres)
{ num_dni = xifres;
}

public int getDNI()


{ return (num_dni);
}
public boolean equals(DNI altre_dni)
{ return (num_dni == altre_dni.getDNI());
}
public Object clone()
{ return (Object)(new DNI(num_dni));
}
public String toString()
{ return (Integer.toString(num_dni));
}
}

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.

3.2.1.2 Exemple d' herència simple: la subclasse


Com definir la classe NIF a partir de DNI? Un NIF és un DNI amb una lletra al final, lletra que es calcula
a partir de les xifres del DNI. Doncs, com a nous atributs tindrem només la lletra del NIF. Com a nous
mètodes tindrem només un mètode que ens permeti preguntar a un objecte de la classe NIF quina és la
seva lletra.

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:

class NIF extends DNI


{
//nou atribut d'instància
private char lletra_nif;

//atribut de classe per a calcular la lletra


private static char[] taula_lletres = {'T','R','W','A','G',
'M','Y','F','P','D',
'X','B','N','J','Z',
'S','Q','V','H','L',
'C','K','E'};

//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);
}

//redefinim el clone de DNI


public Object clone()
{
return (Object)(new NIF(num_dni));
}
//redefinim el toString de DNI
public String toString()
{
//retornem el que retorna la classe DNI
// amb la lletra del nif concatenada al final

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.

Altres exemples clàssics d’herència són:

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.

3.2.1.3 Classes i mètodes abstractes


Una classe abstracta és una classe de la que no es poden crear objectes (no es pot fer un new). La
seva utilitat és permetre que altres classes derivin d’ella, és a dir, la estenguin.

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 ...

Un altre exemple el veureu a l’exercici 3.10

3.2.1.4 Exercici 3.6

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.

3.2.1.5 Exercici 3.7

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

En aquest exercici creem la classe inicial:

Ho farem seguint els passos següents:

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.

3.2.1.6 Exercici 3.8

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.

Reescriviu el mètode toString de CompteCorr, de forma que escrigui el mateix que


CompteBancari afegint si és aquest el titular del compte que ha demanat xecs o no.

La classe CompteEstalvis ens proporcionarà uns interessos. No hi ha comptes diferenciats, tots


tenen el mateix tipus d’interès, indicat per la propietat ‘tipusInteres’. Com en el cas dels ‘xecsEmesos’ no
volem que els mètodes accessors puguin ser reescrits.

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.

3.2.1.7 Exercici 3.9


Anem a representar objecte geomètrics mitjançant classes java. Per això seguirem els següents pasos:

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.

public interface <nom_de_l'interfície>


{
definició_constants

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.

static final <tipus> <nom_Constant> = <valor>;

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.

public [abstract] <tipus> <nom_mètode>(paràmetres);

3.2.3 Herència múltiple en Java


Molts cops ens adonem que una classe podria heretar de més d'una superclasse. Per exemple, un
becari té característiques dels alumnes i dels professors, un monovolum és un cotxe amb certes
característiques d'una furgoneta ... En aquests casos ens trobem davant d'una herència múltiple.

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.

La classe ha de definir i implementar tots el mètodes definits a cada interfície.

3.2.3.1 Exemple d’herència múltiple: la superclasse i la interfície


Posem com a exemple el cas del monovolumen, que hereta alhora de cotxe i de furgoneta. Com ja hem
dit en Java una classe no pot heretar de dues superclasses. La solució és que hereti d'una de les dues, i
que implementi la interfície de l'altre.

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:

• Marca, model i any de compra

• Matrícula

• consum (litres per quilòmetre)

• 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

• el PMA (Pes Màxim Autoritzat).


Definirem, doncs, una interfície Furgoneta que tingui això. Problema: a les interfícies no es poden
definir atributs, només constants o mètodes. La TARA i el PMA no són constants (i, és clar, tampoc són
mètodes). Com ho fem?
El que podem fer és definir una interfície amb els mètodes get’s i set’s a la TARA i el PMA:

Furgoneta.java
public interface Furgoneta
{
//no hi ha constants

//declaració de mètodes

public int getTARA();

public void setTARA(int val_TARA);

public int getPMA();

public void setPMA(int val_PMA);


}

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.

3.2.3.2 Exemple d'herència múltiple: la subclasse


Ara que tenim ja declarats la classe Cotxe i la interfície Furgoneta, podem definir la classe
Monovolumen de la manera següent:

Monovolumen.java
class Monovolumen extends Cotxe implements Furgoneta
{
//declaració d'atributs
protected int valor_TARA, valor_PMA;

//declaració de mètodes

Monovolumen(String fabricant, String mod, int any,


int places, String extres,
String prov_matr, int num_matr, String lletres_matr,
float consum, int tara, int pma)
{
super(fabricant, mod, any,
places, extres,
prov_matr, num_matr, lletres_matr,
consum);

Pàgina 56 de 87
Curs Programació Java nivell bàsic.

valor_TARA = tara;
valor_PMA = pma;
}

//implementació de la interfície Furgoneta


public int getTARA()
{
return (valor_TARA);
}

public void setTARA(int val_TARA)


{
valor_TARA = val_TARA;
}

public int getPMA()


{
return (valor_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 d'excepcions en Java és la següent:

• Error hereta de Throwable

• Exception hereta de Throwable

• IOException hereta d'Exception

• RuntimeException hereta d'Exception

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.

Les excepcions que hereten de RuntimeException inclouen problemes com:

• un accés a una matriu fora del seu rang,

• 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.

• una eliminació no vàlida.


Les excepcions que no hereten de RuntimeException inclouen:
• intentar llegir més enllà de la fi d'un fitxer,

• intentar obrir una adreça d'internet (URL) formada de manera incorrecta.

Pàgina 58 de 87
Curs Programació Java nivell bàsic.

Anunciar les excepcions que llança un mètode


Un mètode Java pot llançar una excepció si troba una situació que no pot gestionar. La idea és simple:
una funció no només diu al compilador de Java quin valor ha de retornar, també diu al compilador què
és el que no va bé.

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:

public <tipus> <nom_mètode>(paràmetres) throws <tipus_excepció>


{
...
}

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.

La regla de Java d'especificació d'excepcions és simple: un mètode ha de declarar totes les


excepcions explícites que llança. És a dir, aquelles que no deriven de la classe Error o de
RuntimeException.

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
{
...

//exemple de declaració amb una excepció


public Image carregarImatge1(String s)
throws IOException
{...}
//exemple de declaració amb multiples excepcions
public Image carregarImatge2(String s)
throws EOFException, MalformedURLException
{...}

...
}

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.

Construïm una excepció anomenada FileFormatException que hereti de IOException.


Construirem dos constructors, un per defecte i un altre on li passem un missatge.

public class FileFormatException extends IOException


{
public FileFormatException()
{
}
public FileFormatException(String missatge)
{
super(missatge);
}
}

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.

Per a capturar una excepció, tenim un bloc try-catch.

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

1. Java omet la resta de codi en el bloc try

Pàgina 60 de 87
Curs Programació Java nivell bàsic.

2. executa el codi de tractament dins de la clàusula catch.


Si cap codi del bloc try llança una excepció, aleshores Java no entra a la clàusula catch.
També podem capturar tipus múltiples d'excepcions en un bloc try i gestionar cada tipus de manera
diferent.
Vegem un exemple d'això. Un error de programació, com pot ser un índex erroni per accedir a un vector,
llança una excepció del tipus RuntimeException. Un intent d'obrir un fitxer que no existeixi llança una
IOException. A l'exemple es poden llençar ambdues excepcions:

• EmptyStackException (una excepció del tipus RuntimeException) que es llança quan es


vol treure un element d'una pila i aquesta està buida.

• IOException, que es llança quan hi ha un problema de lectura d'un fitxer.


L'exemple tracta de treure 100 nombres d'una pila i guardar-los en un fitxer:

...
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();
}
...

3.3.1.1 Exercici 3.10

Afegiu a la jerarquia de classes dels comptes bancaris la creació i captura d’excepcions.

Les situacions anòmales que caldria captura són:

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.

4.- El reintegre ha de ser com a màxim del saldo disponible.

3.3.1.2 Exercici 3.11

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).

Els packges es fan servir amb 3 clares finalitats:

1.- Per agrupar classes relacionades.

2.- Per evitar conflictes de noms.

3.- Per ajudar al control d’accessibilitat de classes i membres.

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:

import corejava.* ;//Importa totes les classes


// en el paquet corejava
import java.util.*;
int i = Console.readInteger();

Pàgina 63 de 87
Curs Programació Java nivell bàsic.

Date today = new Date();

o bé...

import corejava.Console; //Importa només la


// classe Console
import java.util.Date;
int i = Console.readInteger();
Date today = new Date();

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.

3.4.2 Com col·loca el compilador els packages


Tots els fitxers d'un paquet (package) s'han de col·locar en un subdirectori que correspongui al nom
complet del paquet. Per exemple, tots els fitxers del paquet corejava han de passar al subdirectori
corejava. Tots els fitxers del paquet java.util són en el subdirectori java\util (java/util en
Unix).

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.

3.4.3 Àmbit del package


Qualsevol classe pot fer servir els atributs i mètodes marcats amb public. Els marcats amb private
només poden ser utilitzats per la classe que els defineix. Si no s'especifica ni public ni private,
aleshores es pot accedir a la classe, mètode o variable des de tots el mètodes del mateix paquet.

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).

3.4.4 Exercici 3.12


Ara volem reaprofitar codi, una de les meravelles mes meravelloses del Java. Si recordeu, a l’exercici 3.2
vàrem crear la classe Persona. Si recordeu també, a l’exercici 3.6, vàrem crear les classes necessàries
per tractar DNI’s i NIF’s.

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

Modificar els constructors de la classe Persona i el mètode getDni.

Pàgina 65 de 87
Curs Programació Java nivell bàsic.

4 Classes d’utilitat.

4.1 Treballar amb dates i hores.


En aquest cas, podríem dir que Java és el paradigma de com fer difícil allò que sembla fàcil. Treballar
amb dates i hores, en Java, a diferència d’altres llenguatges, no és pas trivial. A continuació es
presenten les classes més rellevats en el tractament de dates i hores.

4.1.1 Classe Date


Representa un instant de temps amb precisió de milisegons. El valor s’emmagatzema com un long de
64 bits que representa els milisegons transcorreguts des de les 00:00:00 del 1 de gener de 1970 GMT
Els mètodes més importants d’aquesta classe són :

Public Date() Constructor per defecte. Crea un date a partir de


la data i hora del sistema.
Public Date (long) Crea un date a partir del número de milisegons
des del 1/1/70
Public boolean after (Date) Indica si la data passada com argument és
posterior a la data representada per l’objecte.
Public boolean before (Date) Indica si la data passada com argument és
anterior a la data representada per l’objecte.

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ó.

4.1.2 Classes Calendar i Gregorian Calendar


La classe calendar és una classe abstracte que disposa de mètodes per convertir objectes de la classe
date en enters que representes dates i hores concretes.
Cal anar amb compte si hem de treballar amb dates antigues, pel tema del canvi de calendari. Si
les dates es troben dintre del calendari gregorià, el millor es fer servir la classe
GregorianCalendar que porta tot un seguit de mètodes per treballar amb dates.
Cal tenir present que java té una forma una mica peculiar, per no dir “rara”, de representar dates i hores,
sobretot pel fet que representa els mesos de l’any per enters entre 0 i 11.

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.

GregorianCalendar() Constructor per defecte. Crea un gc a partir de


la data i hora del sistema.

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.

Date getTime () Retorna el date.


setTime (Date) Estableix el calendar amb la data indicada.

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.

atributs són “normalitzats”. Per exemple, un lenient GregorianCalendar interpreta MONTH ==


JANUARY, DAY_OF_MONTH == 32 com February 1.

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

4.1.3.1 Exercici 4.1


Indiqueu quin és el resultat esperat del següent fragment de codi.
Si cal comproveu-lo executant-los realment.

GregorianCalendar gcAvui = new GregorianCalendar();


System.out.println("Dia avui = " + gcAvui.get(Calendar.DAY_OF_MONTH));
System.out.println("Mes avui = " + gcAvui.get(Calendar.MONTH));

GregorianCalendar gcAltre = new GregorianCalendar(2006, 9, 15);


System.out.println("Altre dia = " + gcAltre.get(Calendar.DAY_OF_MONTH));
System.out.println("Mes altre = " + gcAltre.get(Calendar.MONTH));

4.1.3.2 Exercici 4.2


Indiqueu quin és el resultat esperat del següent fragment de codi.
Si cal comproveu-lo executant-los realment.

GregorianCalendar gcAvui = new GregorianCalendar();


System.out.println("Mes = " + gcAvui.get(Calendar.MONTH));
gcAvui.set(Calendar.DAY_OF_MONTH,31);
System.out.println("Mes = " + gcAvui.get(Calendar.MONTH));
System.out.println("Dia = " + gcAvui.get(Calendar.DAY_OF_MONTH));

4.1.3.3 Exercici 4.3


Indiqueu quin és el resultat esperat del següent fragment de codi.
Si cal comproveu-lo executant-los realment.

GregorianCalendar gcAvui = new GregorianCalendar();


gcAvui.setLenient(false);
System.out.println("Mes = " + gcAvui.get(Calendar.MONTH));
gcAvui.set(Calendar.DAY_OF_MONTH,31);
System.out.println("Mes = " + gcAvui.get(Calendar.MONTH));
System.out.println("Dia = " + gcAvui.get(Calendar.DAY_OF_MONTH));

Pàgina 68 de 87
Curs Programació Java nivell bàsic.

4.1.3.4 Exercici 4.4

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.

4.1.4 Classes DateFormat i SimpleDateFormat


La classe DateFormat és una classe abstracta que pertany, atenció, no al java.util sinó al java.text.
Proveeix mètodes static per convertir strings representant dates en objectes de la classe date i viceversa.
La classe SimpleDateFormat és la única que deriva d’aquesta i és la que normalment farem servir.
El formats són:

Letter Date or Time Component Presentation Examples


G Era designato Text AD
y Year Year 1996; 96
M Month in year Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day in week Text Tuesday; Tue
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
H Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800

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.

Alguns dels exemples més freqüents de format són:

23/12/2006 “dd’/’MM’/’yyyy”
Dilluns 23 de setembre de 2006 “EEEE dd ‘de’ MMMM ‘de’ yyyy”
08:42:03 “HH:mm:ss”

Els mètodes que es fan servir més sovint són:


Constructors:
SimpleDateFormat (String) String és el patró que li indica com formatejar les
dates. Ho farà segons els locale de la màquina.
SimpleDateFormat (String, Locale) String és el patró que li indica com formatejar les
dates. Ho farà segons el locale que se li indiqui.
Podem crear el Locale català amb new
Locale(“CA”);
No constructors:
String format (Date) Dona el String corresponent a formatejar el Date
que reb com a paràmetre, indicat per l’String que
hem posat al constructor.

Pàgina 69 de 87
Curs Programació Java nivell bàsic.

Date parse (String); Cas de poder, parseja l’String rebut com a


paràmetre i el converteix en un Date segons el
format inidicat en el constructor. Si no pot, llença
una ParseException
setLenient(boolean) Té el mateix significat que al calendar.
Habitualment el posarem a false ja que per defecte
està a true.

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.

DateFormat df2 = new SimpleDateFormat("dd'/'MM'/'yyyy");


try
{ Date d = df2.parse("32’/’10’/’2006");
} catch (ParseException e)
{ e.printStackTrace();
}

En canvi aquest sí que farà el que segurament volem.

DateFormat df2 = new SimpleDateFormat("dd'/'MM'/'yyyy");


df2.setLenient(false);
try
{ Date d = df2.parse("32’/’10’/’2006");
} catch (ParseException e)
{ e.printStackTrace();
}

4.1.4.1 Exercici 4.5c

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.

4.1.4.2 Exercici 4.5


Cal implementar la nova classe SimpleDateUB, en un package anomenat edu.ub.utilitats, en un projecte
anomenat Exercici4.5b, que tindrà:
1. un atribut anomenat data de tipus date.
2. un constructor que rep un date com a paràmetre ( i el guarda a l’atribut)
3. un constructor que rep un String i el passa a date, sempre que tingui el format dd/MM/yyyy o
dd/MM/yy o dd-MM-yyyy o dd-MM-yy. Cas contrari llença una excepció.
4. un mètode String getAsText (String format) on si format podrà ser un de 3 possibles 23/10/2006,
23 d’octubre de 2006 o finalment Dilluns 23 d’octubre de 2006. que els clients d’aquesta classe
podran escollir amb 3 atributs statics (constants).
De moment no us preocupeu pel problema dels apòstrofs.
Si cal feu un mètode main per comprovar el funcionament de la classe.
Cal que creeu un fitxer util.jar que contingui aquesta classe.

Pàgina 70 de 87
Curs Programació Java nivell bàsic.

Modificar la classe persona de l’exercici 3.12 per tal que tingui:


un nou atribut anomenat dataNaixement, del tipus SimpleDateUB.
un mètode setDataNaixement que rebi un Date
un mètode setDataNaixement que rebi un String i generi el SimpleDateUB i el guardi a
dataNaixement. Pot llençar una excepció si la data no és correcte.
El projecte ha d’incorporar la llibreria util.jar per tal de tenir accés a SimpleDateUB

4.2 JCF: Java collections Framework

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.

Trobareu informació detallada a http://java.sun.com/docs/books/tutorial/collections/index.html

El framework consta de 3 elements:


• Interfaces: Defineixen els mètodes que han de contenir els diferents tipus de col·leccions
• Implementation: Implementen les interfaces anteriors.
• Algoritmes: Mètodes per fer accions habituals com ordenacions, cerques ... de tal forma que
aquests algoritmes siguin polimòrfics, és a dir, que es puguin cridar independentment del tipus
de col·lecció que es tracti.

4.2.2 Interfaces e Implementacions


Les dues interfaces bàsiques són Collection i Map. A la seva vegada, de Collection deriven 3 interfaces més, com
són Set, List i Queue. De Set deriva SortedSet. De Map deriva SortedMap.

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

Com recórrer un objecte Collection?


Fins a la versió 1.4 només hi havia una forma de recórrer una col·lecció, que era fer servir els iteradors.
A partir de la versió 1.5 ara a més a més es troba la sentència for-each.

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);
}
}
}

Com obtenir un array a partir d’un collection?

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:

Persona[] vp = (Persona[]) c.toArray(new Persona[0]);

I això per què ho hem de voler fer?

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.

Hi ha 3 classes que implementen Set:


• HashSet: Guarda les dades en una HashTable. És la que proporciona millor rendiment, però no
es garanteix cap ordre en els recorregut seqüencial (iterator) dels seus elements.
• TreeSet: Emmagatzema els elements en una estructura en arbre. És més lent que l’anterior.
• LinkedHashSet: És com el primer però a més a més li afegeix una llista per mantenir l’ordre en
que els elements han estat afegits al set. Així supera a limitació del HashSet.

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);
}
}
}

Exemple: Eliminar els duplicats d’una collection.

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.

// Eliminem els duplicats.


Collection noDups = new HashSet(c);

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.3 Exercici 4.7


Comproveu el resultat de l’exemple anterior.

Com farieu per tal que la segona col.lecció fos ordenada ?

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

ListIterator listIterator(); En comptes d’un Iterator retorna un ListIterator


que és un interface que estén iterator, afegint
mètodes per, per exemple, recórrer
ListIterator listIterator(int Index); Igual que l’anterior, però posicionant el cursor en l
element index.

Hi ha 3 classes que implementen llista:


• ArrayList: És la recomana en la majoria dels casos, ja que dona el millor rendiment.
• LinkedList: Ofereix en determinades circumstàncies millor rendiment que ArrayList.
• Vector: Està deprecated. Es manté només per compatibilitat amb versions antigues del JDK.

4.2.2.5 Exercici 4.8


Crear una classe anomenada Contracte.
Té 4 atributs private, id, dataInici, dataFi i sou, les dues dates de tipus SimpleDateUB (recordeu que és
la classe que vàreu crear a l’exercici 4.5) i el sou i el id, de tipus int. Creeu els mètodes set’s i get’s
corresponents i un constructor que rebi les 4 dades com a paràmetre.

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.

A la classe Treballador afegiu el mètode addContracte(Contracte c) que afegeixi el contracte al


treballador.

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.

Hi ha 3 classes que implementen Map:


• HashMap: És habitualment el que dona millor rendiment.
• TreeMap: Dona millor rendiment només en determinades circumstàncies.
• LinkedHashMap: Rendiment similar al HashMap i a més a més preserva l’ordre d’introducció de
les dades.
• Hashtable: Està deprecated. Es manté només per compatibilitat amb versions antigues del
JDK.
El que es fa servir més sovint és el HashMap.

Com iterar sobre un Map?


Tot i que no és el seu ús més habitual, pot sorgir la necessitat de recórrer tots els elements d’un Map, bé
les keys, els valors o els parells key, valor. Per fer-ho la interface Map defineix uns mètodes que
retornen Collection. Una vegada obtinguda la Collection podrem recórrer-la amb un for-each o accedint
al seu iterador.
Els mètodes en qüestió són:
Collection values() Retorna una col·lecció amb els valors del Map.
Cada implementació de Map pot retornar la
implementació de Collection que vulgui.
Set keySet() Retorna un Set amb les keys. És un Set i no
Collection ja que Set no pot tenir duplicats, i les
keys d’un Map, per definició, tampoc.

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"));

// Recorregut seqüencial en ordre arbitrari


Collection c = m.values(); // Ens retorna una col.lectió de la que no en sabem
// realment el tipus que la implementa.
for (Object o:c)
{ System.out.println ((String) o);
}
}
}

El que no es pot fer és for (Object o: m) on m és un map.

4.2.3 Algoritmes. Ordenacions.


Només veurem el tema de les ordenacions.
Per tal que un Collection o Map sigui ordenable cal que la classe de l’objecte que contenen implementi la
interfície “Comparable”. Això per defecte ja ho fa la classe String, però no les classes que nosaltres
creem.
Per implementar “Comparable” cal definir el mètode int CompareTo (Object o) de tal forma que retorni:
0 si o és igual a l’objecte.
-1 si o és més petit que l’objecte.
1 si és més gran que l’objecte.
Cal cridar a Collections.sort(List). Compte, que és Collections i no pas Collection, i que el paràmetre
ha de ser List, no Collection.

Aquí teniu un exemple.

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);
}
}
}

class Persona implements Comparable


{ String dni, nom, cognom1;

Pàgina 76 de 87
Curs Programació Java nivell bàsic.

Persona (String d, String n, String c)


{ dni = d; nom = n; cognom1 = c;
}

public int compareTo(Object o)


{ Persona p = (Persona) o;
return this.dni.compareTo(p.dni);
}
}

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).

Aquí teniu un exemple.

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);
}
}
}

class Persona implements Comparable


{ String dni;
String nom;
String cognom1;
Persona (String d, String n, String c)
{ dni = d;
nom = n;
cognom1 = c;
}

public int compareTo(Object o)


{ Persona p = (Persona) o;
return this.dni.compareTo(p.dni);
}
}

class ComparadorPerNomCognom implements Comparator


{
public int compare(Object o1, Object o2)
{ Persona p1 = (Persona) o1;
Persona p2 = (Persona) o2;
String aux1 = p1.cognom1 + p1.nom;
String aux2 = p2.cognom1 + p2.nom;
return aux1.compareTo(aux2);
}

Pàgina 77 de 87
Curs Programació Java nivell bàsic.

4.2.4 Exercici 4.9


Afegiu a la classe Treballador un mètode que retorni un mètode getContractesDesc que retorni un Array
de Contractes ordenats descendenment per data inici, és a dir, primer el més nou i últim el més antic.

4.2.5 Exercici 4.10


Modifiqueu l’exemple de recorregut del Map per tal que recorri les keys en ordre alfabètic.

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

Teniu el manual d’introducció de SUN traduït al castellà en:


http://www.programacion.com/java/tutorial/jdbc/
Queda també fora de l’abast d’aquest curs temes com:
Els pools de connexions, tan útils en entorns multiusuari com les aplicacions web.
Eines o mecanismes de persistència OOR, com JDO, EJB 3.0, Hibernate, Top Link.

5.1 JDBC 1.0


Aquesta versió del API originada amb el JDK 1.1 inclou la majoria de les funcionalitats bàsiques
requerides per tota aplicació Java que requereixi accés a base de dades, i que s’han mantingut en les
següents revisions, jdbc 2.0 i 3.0

A continuació és presenten les accions bàsiques a realitzar per accedir a bases de dades des de java.

5.1.1 Establiment de la connexió

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.

5.1.1.1 Carregar el Driver


Per poder utilitzar el controlador del SGBD que hem escollit, primer hem de carregar el
controlador. Per fer-ho s’utilitza el següent codi:

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ó
}

5.1.1.2 Fer la Connexió.


Cal ara cridar al Driver Manager per obtenir un objecte Connection, indicant la url de la base de dades a
la que ens volem connectar, així com el codi i contrasenya de l’usuari de la base de dades

Connection con = DriverManager.getConnection(url, "myLogin", "myPassword");

La documentació del fabricant del driver ens dirà exactament quina url posar. Concretament en el cas
d’Oracle caldria fer quelcom com:

Connection con = DriverManager.getConnection(“jdbc:oci8:nomServei, "myLogin", "myPassword");

5.1.2 Obtenció de l’objecte necessari per executar sentències SQL

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

// S’ha omès, per simplicitat, el tractament d’excepcions

// 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.

5.1.3 Execució de la sentències SQL.

A partir del Statement: podrem cridar bàsicament a dos mètodes:

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%');

Amb el PreparedStatement: La característica principal d’un objecte PreparedStatement és que, al


contrari que l’objecte Statement, se li entrega una sentència SQL quan es crea. El principal avantatge és
que en la majoria dels casos, aquesta sentència SQL s’enviarà al controlador de la base de dades
immediatament, on serà compilada. Como a resultat, l’objecte PreparedStatement no només conté la
sentencia SQL, sinó una sentència SQL que ha estat precompilada. Això significa que quan s’executi la
PreparedStatement, el controlador de la base de dades podrà ejectar-la sense haver de compilar-la
primer, fet que comporta un estalvi de temps considerable.

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");

int nombreFilesAfectades = preStmt.executeUpdate();

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.

Amb el PreparedStatement també tenim la distinció entre executeUpdate i executeQuery.

5.1.4 Obtenció dels resultats de les consultes SQL


L’execució d’una comanda SQL ens retorna una taula accessible mitjançant un objecte del tipus
ResultSet. Aquest objecte ens proporciona un conjunt de mètodes i propietats per a llegir les dades. El
següent codi permet veure com accedim a les dades de dins del ResultSet

Statement stmt = connexio.createStatement();


ResultsetSet resultSet = stmt.executeQuery("SELECT * FROM TAULA");

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.5 Tancant objectes


Una vegada no es vagin a fer servir, és necessari tancar els objectes resultSet, Statement i Connection
mitjançant els respectius mètodes .close()

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.

5.1.6.1 Desactivar el mode “Auto-entrega”


Quan es crea una connexió, aquesta estén en mode “auto-entrega”. Això vol dir que cada
sentència SQL individual es tractada com una transacció en sí mateixa i serà automàticament
entregada just després de ser executada.
La manera de permetre que dues o més sentències siguin agrupades en una transacció és
desactivar el mode auto-entrega. Cal establir el AutoCommit a false.

// Es suposa que con és la connexió activa


con.setAutoCommit(false);

5.1.6.2 Entregar una Transacció


Una vegada que s’ha desactivat l’auto-entrega, no s’entregarà ninguna sentència SQL fins que cridem
explícitament al mètode commit. El següent codi, en el que con és una connexió activa, il·lustra una
transacció.

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.

5.1.6.3 Quan cridar al mètode rollback


Cridar al mètode rollback avorta la transacció i torna qualsevol camp o registre que fora modificat, als
seus valors anteriors. Si estem intentant executar una o més sentències en una transacció i obtenim una
SQLException, hauríem de cridar al mètode rollback per avortar la transacció i, si cal, començar-la de
nou.

5.1.7 Exemple sencer d’accés a base de dades

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/

public class OfertaDAO extends BaseDAO


{
public OfertaDAO() throws NamingException
{ super();
}

public GrupGiga[] getGrupsGigaDelGIGA(String curs, String codiGigaAssig, String semestre)


throws SQLException {
Statement stmt = null; Connection con = null; ResultSet rs = null;
String query = null; GrupGiga grupGiga = null;
ArrayList res = new ArrayList();

query = "SELECT a.numalumnes, a.codi_assig, a.quad, a.curs, a.grup_giga"+


" FROM v_giga_num_matriculats a"+
" WHERE a.curs = '"+curs+"'"+
" AND a.codi_assig = '"+codiGigaAssig+"'"+
" and a.quad = '"+semestre+"'";
try
{ con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery(query);
while ( rs.next() )
{ grupGiga = new GrupGiga();
this.omplirDadesGrupGiga(grupGiga, rs);
grupGiga.setQuadrament(GrupGiga.Egi);
res.add(grupGiga);
}
if(rs != null) rs.close();
}
catch (SQLException se)
{ logger.error("Query: "+query,se);
throw se;
}
finally
{ tancarConStmt(con, stmt);

Pàgina 83 de 87
Curs Programació Java nivell bàsic.

}
return((GrupGiga[])res.toArray(new GrupGiga[res.size()]));
}

// Exemple de sentència d’actualització de dades


public void setPraGrup(OfertaDTO oferta, GrupGiga grup, String idPersonalPra) throws
SQLException {
ArrayList accioBD = new ArrayList();
accioBD.add ("alter session set NLS_TERRITORY=SPAIN");
accioBD.add( "UPDATE gradadm.gpod_pra SET" +
" id_personal = "+idPersonalPra+
" WHERE idassignatura = "+oferta.getIdAssignatura()+
" and curs ='"+oferta.getCurs()+"'"+
" and oferta= "+oferta.getOfertaPK().getOferta()+
" and codi_grup_giga ='"+grup.getIdGrupGiga()+"'");
}
executarTransaccio(accioBD);
}

package ub.ges.util.bd;

//SQL
import ...

public class BaseDAO


{ public static DataSource ds;

public BaseDAO() throws NamingException


{ try
{ // Cerca el datasource
InitialContext ic = new InitialContext(); ds = (DataSource) ic.lookup("jdbc/GRADDDS");
}.
catch (NamingException ne)
{ logger.error("EXCEPTION",ne);
throw ne;
}
}

/**
* 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.

// Executar les accions


while (accions.hasNext());
try
{ stmt.executeUpdate((String) accions.next());
}
catch(SQLException sqlEx)
{ con.rollback();
tancarConStmt(con, stmt);
throw sqlEx;
}
}
con.commit();
tancarConStmt(con, stmt);
}

/**
* 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;
}

query = "SELECT " + seq + ".nextval as identif from dual";


try
{ rs = stmt.executeQuery(query);
rs.next();
seguent = rs.getLong("identif");
}
catch( SQLException sqlEx2)
{ tancarConStmt(con, stmt);
throw sqlEx2;
}
tancarConStmt(con, stmt);
return (seguent);
}

/**
* 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.

}
}
}

5.2 JDBC 2.0


No ho veurem en aquest curs, però algunes de les “noves features” que va introduir JDBC 2.0, que va
aparèixer amb el JDK 1.2 en front JDBC 1.0 de la versió original de Java, van ser:

• 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.

5.3 JDBC 3.0


No ho veurem en aquest curs, però algunes de les “requete noves features” que va introduir JDBC 3.0,
que va aparèixer amb el JDK 1.4 en front de les versions prèvies de JDBC, van ser:

• 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

5.4.1 Exercici 5.1

Anem a crear la capa DAO per la clase Persona i Alumne.


Creem una clase anomenada PersonaDAO que en el seu constructor carregi el driver de BD.

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.

Li afegim un mètode Persona insertPersona(Persona p) que gravi la persona a la base de dades.

Creem un mètode main per tal de provar el funcionament del getPersona.

5.4.2 Exercici 5.2


Ara podem fer la sofisticació del mètode getPersonaByDNI de tal forma que si el tipus de persona és
treballador, ompli la col.lecció de contractes de la persona i retorni un objecte de tipus treballador.

Pàgina 87 de 87

You might also like