Diferència entre revisions de la pàgina «M3 - Programació estructurada / Continguts UF2: Classes i biblioteques»

De wikiserver
Dreceres ràpides: navegació, cerca
(L’API del llenguatge Java)
(L’API del llenguatge Java)
Línia 209: Línia 209:
 
referir-se a l’API només per estudiar amb més detall quins mètodes ofereix.
 
referir-se a l’API només per estudiar amb més detall quins mètodes ofereix.
  
[[Imatge:m3uf2_classes_i_biblioteques_2.png |7500px|center| Classes i biblioteques]]
+
[[Imatge:m3uf2_classes_i_biblioteques_2.png |750px|center| Classes i biblioteques]]
  
 
Com a exemple, entre els paquets que contenen les classes més populars, podeu trobar:
 
Com a exemple, entre els paquets que contenen les classes més populars, podeu trobar:

Revisió del 12:30, 13 març 2018

Programes amb múltiples classes

  • La manera més directa de fer un programa modular és establir una correspondència un a un entre mòduls i fitxers on està escrit el codi font d’un programa.
  • Cada mòdul es representa amb un fitxer de codi font diferent.
  • En el cas de Java, un programa modular està compost de l’agregació de múltiples classes.

Què és una classe?

Tres consideracions des d'una perspectiva pràctica:

  • Un programa en Java. Els fitxers dels programes, pròpiament, són classes (al cap i a la fi, s’inicien amb la declaració public class...). En aplicar disseny descendent, el seu codi queda distribuït en un mètode principal (main), que indica la seva primera instrucció i el punt d’inici del seu flux de control, junt amb diferents mètodes addicionals que poden ser invocats directament.
  • Un repositori de mètodes. També s'usa el terme classe per referir-se a biblioteques de mètodes, que actuen com extensions en les instruccions disponibles per defecte en el llenguatge. Abans de poder fer-ho, però, cal inicialitzar-les correctament.
-L’exemple més clar és la classe Scanner, que ofereix un repertori de mètodes per controlar la lectura de dades des del teclat (nextLine(), nextInt(),hasNextFloat(), etc.).
  • Un tipus compost. Aquest mateix terme s'usa com a sinònim de tipus compost.
- l’exemple per antonomàsia és la classe String, utilitzada per referir-se a cadenes de text dins de Java. Els tipus compostos de Java permeten manipular dades complexes mitjançant la invocació de mètodes (charAt(...), indexof(...), etc.).

Semblences

- Els tres casos són exactament el mateix en darrera instància: codi font dins un fitxer anomenat NomClasse.java, amb la declaració public class NomClasse..., i estructurat com un seguit de mètodes declarats dins seu.
- Per tant, la classe Scanner ha estat desenvolupada per algú altre, dins d’un fitxer anomenat Scanner.java i que conté diferents mètodes.

Estructura d’un programa modular en Java

  • Totes les classes es codifiquen de la mateixa manera (com fitxers que contenen un seguit de mètodes que poden ser invocats).
  • Un programa és una seqüència ordenada d’instruccions que es van executant d’inici a fi.
- Mitjançant les estructures de control (selecció i repetició), és possible crear bifurcacions o bucles a la seqüència.
- Es poden trobar invocacions a mètodes, fent possible distribuir les instruccions en blocs diferents, que poden ser executats repetides vegades en diferents moments del procés.
- Tots els mètodes estan escrits dins un mateix fitxer, que conté el codi font de tot el programa.
- main és el mètode principal, el qual indica quina és la primera instrucció.
  • L’única diferència d’un programa modular en Java és que els mètodes, en lloc d’estar escrits tots en el mateix fitxer, estan distribuïts dins de diferents fitxers (diferents classes). tal com es contrasta a la figura 1.1.
  • Exemple, el programa modular es composa de tres fitxers diferents, anomenats Principal.java, Modul1.java i Modul2.java.
Classes i biblioteques
  • L’escriptura de mètodes en fitxers separats se sol fer d’acord a algun criteri d’ordre, com agrupar mètodes per funcionalitats semblants (una classe amb els mètodes relacionats amb operar amb arrays, una altra amb els que llegeixen dades des del teclat, etc.).
  • Per fer un programa modular cal decidir amb criteri com distribuir els diferents mètodes en diferents classes (i en quantes) i saber com invocar mètodes declarats a altres classes.
  • Main class: és l’única que disposa d’un mètode principal declarat en el seu codi.
  • Per executar un programa modular en Java, només cal executar aquesta classe principal. A partir d’aquí, l’execució de les diferents instruccions segueix el flux de control habitual, partint del mètode principal d’aquesta classe, tal com s’ha mostrat a la figura.
  • Les classes addicionals normalment tenen dos orígens. Poden ser classes creades per vosaltres mateixos, o bé creades per altres desenvolupadors. En qualsevol dels dos casos, totes estan declarades i codificades en fitxers .java per separat.

Definició de classes addicionals

  • Per dividir un programa en classes diferents, només cal crear tants fitxers com classes es vol, cadascun amb el seu nom i definició pròpia.
  • La classe principal ha de contenir com a mínim els mètodes main i inici.
  • La resta de classes contindrà els mètodes que es vulgui distribuir.
  • Excepte pel mètode principal a les classes addicionals, totes les classes són exactament iguals a nivell de sintaxi.

Ús de classes addicionals

  • En un programa modular, des d’una classe s’invoquen mètodes declarats a una classe diferent. Però cada mètode només està escrit un únic cop entre totes les classes del programa.
  • Per invocar mètodes escrits en fitxers diferents, primer cal un pas previ d’inicialització, a partir del qual es permet la invocació dels mètodes externs. En dur a terme aquest procés, s’assigna un identificador a partir del qual és possible invocar els mètodes d’aquella classe, usant-lo com a prefix a la invocació.
  • La sintaxi per fer-ho és la següent:
NomClasse identificador = new NomClasse();
identificador.nomMètode(paràmetres);
  • La inicialització només es fa una vegada.
  • L’àmbit i la validesa de l’identificador és el mateix que una variable.

Biblioteques de classes: paquets

  • Quan el nombre de classes resultants sigui força gran és convenient organitzar conjunts de classes dins d’un programa. Això permet aplicar modularitat a conjunts de classes en bloc, i també fer-les més fàcils de localitzar i gestionar.
  • Una biblioteca de classes, o package en Java, és un conjunt de classes vinculades entre elles d’acord a algun criteri temàtic o d’organització del seu codi.
  • Els criteris per decidir com dividir les classes d’un programa en conjunts de paquets (packages) diferents són subjectius.
  • Malgrat que els programes fets i que farem tenen un nombre de classes massa limitat com per justificar de manera clara l’ús de paquets, es tracta d’un element prou important de Java com per fer necessari conèixer el seu funcionament.

Definició de paquets

  • Per assignar un conjunt de classes a un package, primer cal triar un identificador (autoexplicatiu), que servirà

com el nom d’aquest.

  • Per fer que una classe hi pertanyi, a la primera línia del seu fitxer amb el codi font s’ha d'escriure la sentència següent:
package identificadorPackage;
  • El concepte package en Java no té una entitat pròpia diferenciada, serà donat implícitament per totes les classes que es declaren com a part d’ell en el seu codi font.
  • Convenció de codi: els noms dels packages s’escriuen sempre tots en minúscula i separant paraules diferents per

un punt. Per exemple:

package uf2.apartat1.exemple1;
  • Totes les classes del Java pertanyen a algun paquet. En cas de no incloure cap sentència import, es considera que aquella classe pertany a un package especial anomenat per defecte (default package). No és possible crear una classe que “no pertanyi a cap package”.
  • La manera com té el Java d’ordenar les classes dins un programa en packages (inclòs el package per defecte) comporta dues restriccions que heu de tenir sempre en compte:
- Donada una classe, aquesta únicament pot pertànyer a un package.
- Donat un paquet, a dintre seu mai hi poden haver dues classes amb el mateix nom.

Ús de classes d’altres paquets

  • El nom qualificat d’una classe és la combinació de l’identificador del seu package junt amb el seu nom, separats per un punt.
  • Només es poden usar directament classes amb què comparteixi el mateix nom de paquet. Si s’usa una classe d’un de diferent, el compilador donarà un error, dient que no la reconeix.
  • Java ofereix tres maneres per indicar quina s’està usant:
-1. Inicialització usant el nom qualificat per al cas de classes d’altres paquets:
package uf2.apartat1.exemples;

public class RegistreNotes {
  ...
  //Ús del nom qualificat per accedir a una classe d’un altre package
  utilitats.arrays.CalculsArrayReals calculador = new utilitats.arrays.CalculsArrayReals();
  ...
}

package utilitats.arrays;

public class CalculsArrayReals {
  //Codi
  ...
}
- 2. Importació explícita a la capçalera del fitxer de codi font, entre la declaració del package i

la declaració public class.... Cal especificar el nom qualificat de la classe que es vol usar.

La sintaxi general és:
import nomQualificat;
  • Cal posar tantes sentències import com correspongui.
  • Les relacions de jerarquia entre els identificadors del package no importen, cal posar cada classe amb el seu package explícitament, una per una.
package uf2.apartat1.exemples;

//Cal importar la classe "CalculsArrayReals", ja que és d’un altre package
import utilitats.arrays.CalculsArrayReals;

public class RegistreNotes {
  //Codi
  ...
}

package utilitats.arrays;
//No s’usa cap classe fora d’aquest package, no s’importa res

public class CalculsArrayReals {
  //Codi
  ...
}
- 3. Importació general. Permet importar automàticament totes les classes dins una biblioteca. Aquest es fa servir sovint quan es volen usar moltes classes del mateix package i importar-les una a una es fa pesat. Es tracta d’usar un asterisc, “*”, en lloc del nom de la classe en el nom qualificat. Aquest fa de comodí i equival a dir “absolutament totes les classes del package”.
package uf2.apartat1.exemples;

//S’importarien totes les classes del package utilitats.arrays
import utilitats.arrays.*;

public class RegistreNotes {
  //Codi
  ...
}

L’API del llenguatge Java

Per realitzar programes modulars no sempre és necessari crear tots i cadascun dels mòduls que formen part del programa. Per sort, sovint els llenguatges de programació incorporen biblioteques de mòduls auxiliars que ja han estat completament desenvolupats pels creadors del llenguatge o altres col·laboradors. Aquests mòduls auxiliars estenen el llenguatge de programació, oferint funcionalitats que van més enllà del que permet la seva sintaxi estrictament o incorporant l’opció d’executar blocs de codi que resolen tasques que es consideren de propòsit general i que poden ser d’utilitat en una àmplia gamma de programes. En el cas del llenguatge Java, el seu kit de desenvolupament (JDK) incorpora un quantiós repositori de classes, organitzades per diferents packages d’acord a la seva temàtica, que poden ser accedides lliurement en realitzar qualsevol programa. Aquest repositori és el que s’anomena l’API de Java. Ara bé, l’objectiu d’aquesta secció no és conèixer totes les classes disponibles, sinó simplement que tingueu un marc general sobre com cal usar-ne una que sigui senzilla, un cop ja us és coneguda la seva existència i que pot ser útil per fer un programa. Si observeu la documentació de l’API de Java, de la qual la figura següent mostra una idea de la seva estructura, veureu que ofereix un enorme repertori de classes que contenen mètodes amb funcionalitats molt diverses, cosa que, de vegades, fa ben complicat trobar d’entre totes la classe que conté els mètodes ideals per a cada cas, si és que existeix. De fet, podeu considerar que intentar esbrinar si hi ha una classe que conté mètodes que us puguin resultar útils als vostres programes a partir d’aquesta documentació és inviable. La documentació es va crear partint del supòsit que ja sabeu el nom de la classe que voleu utilitzar. Per tant, l’aproximació correcta per usar-la és cercar quina classe pot ser la que realitza les tasques que voleu dur a terme, a partir d’una font bibliogràfica externa o d’una cerca a internet, i llavors referir-se a l’API només per estudiar amb més detall quins mètodes ofereix.

Classes i biblioteques

Com a exemple, entre els paquets que contenen les classes més populars, podeu trobar: y java.lang: conté totes les classes vinculades a operacions essencials dels tipus de dades del llenguatge. y java.util: una mena de calaix de sastre amb classes de propòsit general. y java.io: conté totes les classes vinculades a entrada / sortida (tractament de fitxers). y javax.swing: conté les classes bàsiques vinculades a la creació d’interfícies gràfiques. L’avantatge d’aquesta aproximació és que, com que aquestes classes ja estan creades i incorporades com a part del llenguatge, si en trobeu una que ja faci la feina requerida, us estalviareu haver d’escriure parts de codi font del programa.

Mètodes estàtics

Per norma general, per poder invocar mètodes d’una classe cal inicialitzar-la prèviament. Ara bé, d’entre tots els mètodes proporcionats dins de les classes disponibles a l’API de Java, hi ha un petit subconjunt amb una peculiaritat. Els mètodes estàtics poden ser invocats sense haver d’inicialitzar la seva classe. S’identifiquen perquè a la documentació apareixen marcats amb la paraula clau static. Novament, aquesta secció se centra en l’ús dins del context de l’API de Java, i no pas en com generar-ne a les vostres classes o quina és la seva justificació dins de Java. Si bé l’explicació és genèrica, se centrarà en les dues classes més importants basades en aquests tipus de mètode, les quals us poden ser de gran ajut per fer els vostres programes: java.lang.Math i java.util.Arrays. Si mireu la documentació d’aquestes dues classes, veureu que gairebé tots els seus mètodes són estàtics. A la figura següent podeu veure un detall d’alguns dels mètodes de la classe Math. Fixeu-vos com estan identificats amb la paraula static a l’inici de la seva declaració.

Classes i biblioteques

Per invocar aquests mètodes, la sintaxi correcta és posar com a prefix el nom de la classe directament, en lloc de l’identificador fruit de la inicialització. A part d’això, el seu comportament és idèntic a qualsevol altre mètode (com una expressió que avalua a un resultat).

Per exemple, donat el mètode estàtic sqrt definit a la classe Math, el qual accepta un únic paràmetre d’entrada de tipus real, per invocar-lo i desar el resultat en una variable només caldria el codi que es mostra tot seguit. En aquest cas, es calcula l’arrel quadrada de 36. double resultat = Math.sqrt(36);

La classe Math

Aquesta classe pertany al package java.lang, i per tant pot ser usada sense haver d’importar-la. Ofereix un ventall de mètodes estàtics per realitzar operacions matemàtiques avançades, que no es poden dur a terme amb cap dels operadors aritmètics de què disposa Java (suma, resta, multipliació, divisió i mòdul). Tot seguit es mostren alguns dels mètodes més rellevants, associats a operacions matemàtiques relativament comunes i simples.

Mètode Descripció Exemples
abs( x ) valor absolut de x abs( 23.7 ) és 23.7 / abs( –23.7) és 23.7
ceil( x ) arrodoneix x a l’enter més petit que no sigui menor de x ceil( 9.2 ) és 10.0 / ceil( -9.8 ) és -9.0
cos( x ) cosinus trigonomètric de x (x està en radians) cos( 0.0 ) és 1.0
exp( x ) mètode exponencial e x exp( 1.0 ) és 2.71828
floor( x ) arrodoneix x a l’enter més gran que no sigui més gran que x floor( 9.2 ) és 9.0 / floor( -9.8 ) és -10.0
log( x ) logaritme natural de x (base e) log( Math.E ) és 1.0
max( x, y ) el valor més gran de x i y max( 2.3, 12.7 ) és 12.7
min( x, y ) el valor més petit de x i y min( 2.3, 12.7 ) és 2.3
pow( x, y ) x elevat a la potència y pow( 2.0, 7.0 ) és 128.0
sin( x ) sinus trigonomètric de x (x està en radians) sin( 0.0 ) és 0.0
sqrt( x ) arrel quadrada de x sqrt( 900.0 ) és 30.0
tan( x ) tangent trigonomètrica de x (x està en radians) tan( 0.0 ) és 0.0

La classe Arrays

Aquesta classe proporciona mètodes estàtics per manipular taules. Proporciona mètodes com sort per ordenar, binarySearch per buscar en una taula ordenada, equals per comparar-les i fill per posar valors. En el programa següent podem veure la utilització d’aquests mètodes. public class UsArrays { private int arrayInt[] = {1, 2, 3, 4, 5, 6}; private double arrayDouble[] = {8.4, 9.3, 0.2, 7.9, 3.4}; private int arrayIntPle[], copiaArrayInt[]; public UsArrays() { arrayIntPle = new int[10]; copiaArrayInt = new int[arrayInt.length]; Arrays.fill(arrayIntPle, 7); Arrays.sort(arrayDouble); System.arraycopy(arrayInt, 0, copiaArrayInt, 0, arrayInt.length); } public void imprimirArrays() { System.out.print("arrayDouble: "); for (double valorDouble : arrayDouble) { System.out.printf("%.1f ", valorDouble); } System.out.print("\narrayInt: "); for (int valorInt : arrayInt) { System.out.printf("%d ", valorInt); } System.out.print("\narrayIntPle: "); for (int valorInt : arrayIntPle) { System.out.printf("%d ", valorInt); } System.out.print("\ncopiaArrayInt: "); for (int valorInt : copiaArrayInt) { System.out.printf("%d ", valorInt); } System.out.println("\n"); } public int buscarUnInt(int valor) { return Arrays.binarySearch(arrayInt, valor); } public void imprimirIgualtat() { boolean b = Arrays.equals(arrayInt, copiaArrayInt); System.out.printf("arrayInt %s copiaArrayInt\n", (b ? "==" : "!=")); b = Arrays.equals(arrayInt, arrayIntPle); System.out.printf("arrayInt %s arrayIntPle\n", (b ? "==" : "!=")); } public static void main(String args[]) { UsArrays usArrays = new UsArrays(); usArrays.imprimirArrays(); usArrays.imprimirIgualtat(); int ubicacio = usArrays.buscarUnInt(5); if (ubicacio >= 0) { System.out.printf( "S'ha trobat el 5 en el element %d de arrayInt\n", ubicacio); } else { System.out.println("No s'ha trobat el 5 en arrayInt"); } ubicacio = usArrays.buscarUnInt(8763); if (ubicacio >= 0) { System.out.printf( "S'ha trobat el 8763 en el element %d de arrayInt\n", ubicacio); } else { System.out.println("No s'ha trobat el 8763 en arrayInt"); } El mètode binarySearch funciona de la següent manera: si es troba el valor retorna l’índex de l’element, en cas contrari torna un valor negatiu. El valor negatiu es basa en el punt d’inserció de la clau de cerca: l’índex on s’hauria d’inserir la clau si s’hagués de fer una operació d’inserció. Una vegada el mètode determina el punt d’inserció, canvia el signe d’aquest a negatiu i li resta un. Per exemple en el codi anterior el punt d’inserció per al valor 8763 es l’índex 6, per tant el mètode retorna -7. Aquest valor de retorn és útil per agregar elements en una taula ordenada.

Si passem una taula desordenada el valor retornat és indefinit. Si hi ha valors repetits, el mètode no garanteix, quin d’ells troba.

Javadoc

Sintaxi general

Paraules clau