curs java nivell basic v1.1

87
Curs Programació Java nivell bàsic. Pàgina 1 de 87 Curs Java nivell bàsic. Creat per Julio Peñuela Gil Email: [email protected] Versió 1.1 Març 2007

Upload: others

Post on 16-Oct-2021

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 1 de 87

Curs Java nivell bàsic.

Creat per Julio Peñuela Gil Email: [email protected]

Versió 1.1 Març 2007

Page 2: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 2 de 87

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

Page 3: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 3 de 87

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

Page 4: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 4 de 87

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.

Page 5: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 5 de 87

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

Page 6: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 6 de 87

• 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

Page 7: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 7 de 87

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

Page 8: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 8 de 87

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.

Page 9: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 9 de 87

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.

Page 10: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 10 de 87

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

Page 11: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 11 de 87

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

Page 12: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 12 de 87

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:

Page 13: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 13 de 87

//Aquest comentari només pot ocupar una línia //Aquesta és la segona línia del comentari

Page 14: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 14 de 87

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

Page 15: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 15 de 87

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

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

Màx: 127

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

Màx: 32767

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

Màx: 214748364

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

Màx: 9223372036854775808

Page 16: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 16 de 87

Mín: Positiu: 1.40239846e-45 Negatiu: -3.40282347e38

float Nombre amb coma flotant 32 bits

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

Mín: Positiu: 4.94065645841246544e-324 Negatiu: -1.79769313486231570e308

double Nombre amb coma flotant 64 bits

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

Page 17: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 17 de 87

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

i

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

Page 18: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 18 de 87

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.

Page 19: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 19 de 87

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:

Byte, short, int

Dígits decimals (que no comencin per 0) 0x seguit de dígits hexadecimals; per exemple, 0xFF12 0 seguit de dígits octals, per exemple 0726

Long Igual que el tipus int, però seguit del caràcter I o L; per exemple, 1234L, 0x12FABL, 0345345L, 11234I

Float Dígits amb un punt decimal i/o exponent, seguits del caràcter f o F; per exemple, 1.234f, 1.234E+5F

double Igual que el tipus float, però sense el sufix f o F i amb el sufix opcional D; per exemple, 1.234D, 1.234, 1.234E+5

boolean true o false

char 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. Una seqüència d'escapament predefinida entre apòstrofs; per exemple, '\t', '\012'

String Seqüència de caràcters o seqüències d'escapament entre cometes, per 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ó.

Page 20: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 20 de 87

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

Page 21: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 21 de 87

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 Autodecrement

1 (major preferència) Dreta

+,- Més Unari Menys Unari 2 Dreta

* Multiplicació 4 Esquerra

/ Divisió 4 Esquerra

% Ròssec 4 Esquerra

+,- Suma Resta 5 Esquerra

A la taula anterior trobem dos camps especials: la preferència entre operadors i l'associativitat de cada operador.

Page 22: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 22 de 87

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 funció d'un tercer

14 Dreta

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

Page 23: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 23 de 87

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

Page 24: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 24 de 87

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

Page 25: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 25 de 87

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>

Page 26: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 26 de 87

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.

Page 27: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 27 de 87

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

Page 28: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 28 de 87

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.

Page 29: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 29 de 87

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

Page 30: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 30 de 87

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.

Page 31: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 31 de 87

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

Page 32: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 32 de 87

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

Page 33: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 33 de 87

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)

Page 34: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 34 de 87

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.

Page 35: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 35 de 87

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

Page 36: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 36 de 87

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 mateix package

Si Si No Si

Des de altre classe d’altre package

Si No No No

Des de una subclasse del mateix package

Si Si No Si

Des de una subclasse d’altre package

Si No No Si

Page 37: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 37 de 87

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:

...

Page 38: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 38 de 87

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.

Page 39: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 39 de 87

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

Page 40: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 40 de 87

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.

Page 41: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 41 de 87

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.

Page 42: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 42 de 87

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

Diu si l'string i altre_string són iguals, sense 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, caràcter_nou)

retorna un string que resulta de la substitució en 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

Page 43: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 43 de 87

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;

Page 44: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 44 de 87

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

Page 45: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 45 de 87

a = Integer.parseInt(str);

Page 46: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 46 de 87

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.

Page 47: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 47 de 87

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

Page 48: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 48 de 87

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

Page 49: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 49 de 87

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

Page 50: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 50 de 87

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.

Page 51: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 51 de 87

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.

Page 52: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 52 de 87

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:

Page 53: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 53 de 87

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.

Page 54: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 54 de 87

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

Page 55: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 55 de 87

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

Page 56: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 56 de 87

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

Page 57: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 57 de 87

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

Page 58: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 58 de 87

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.

Page 59: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 59 de 87

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.

Page 60: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 60 de 87

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

Page 61: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 61 de 87

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:

Page 62: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 62 de 87

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

Page 63: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 63 de 87

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

Page 64: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 64 de 87

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

Page 65: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 65 de 87

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.

Page 66: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 66 de 87

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.

Page 67: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 67 de 87

GregorianCalendar (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

GregorianCalendar (int year, int month, int dayOfMonth, int hour, int minute)

El mateix que l’anterior, però fins al minut.

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

El mateix que l’anterior, però fins al minut.

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

Page 68: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 68 de 87

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

Page 69: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 69 de 87

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.

Page 70: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 70 de 87

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.

Page 71: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 71 de 87

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.

Page 72: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 72 de 87

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?

Page 73: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 73 de 87

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

Page 74: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 74 de 87

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

Page 75: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 75 de 87

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

Page 76: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 76 de 87

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;

Page 77: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 77 de 87

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

Page 78: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 78 de 87

}

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.

Page 79: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 79 de 87

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.

Page 80: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 80 de 87

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

Page 81: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 81 de 87

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

Page 82: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 82 de 87

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

Page 83: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 83 de 87

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

Page 84: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 84 de 87

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

Page 85: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 85 de 87

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

Page 86: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 86 de 87

} } }

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.

Page 87: Curs Java nivell basic v1.1

Curs Programació Java nivell bàsic.

Pàgina 87 de 87

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.