|
|
|
|
Una matriu és un tipus d'estructura molt senzill, massa.
Des del punt de vista del programador novell, les matrius tenen un inconvenient
fonamental que consisteix en què, abans de poder fer res amb una
matriu, ni tan sols emmagatzemar-hi valors, cal declarar-ne la longitud:
|
|
|
int[]
matriuDEnters=new int[15];
// La matriu tindrà 15 nombres |
|
|
|
o bé |
|
|
String[]
matriuDeParaules=new String[8];
// Contindrà 8 paraules |
|
|
|
o bé |
|
|
Object[]
matriuDObjectes=new Object[12];
// Contindrà 12 objectes |
|
|
|
o bé... |
|
|
Això implica
que el programador, en declarar la longitud de la matriu, ha d'estar molt
segur que no necessitarà afegir-li més elements, que en cap
punt de la resta del programa, un índex s'escaparà i voldrà
afegir elements a una matriu que ja és plena, que la Màquina
Virtual no li escopirà cap ArrayIndexOutOfBoundsException! |
|
|
|
|
|
El SDK
de Java
proporciona diverses solucions a aquest problema. La primera resulta d'un
ús eficaç dels objectes de la classe java.util.Vector.
En aquesta pràctica analitzaràs els recursos disponibles
en aquesta classe i els avantatges que t'ofereix enfront de les matrius.
- Començaràs amb dos projectes senzills que construiran,
de dues maneres diferents, la llista de divisors d'un nombre enter i
et permetran veure que, a diferència del que passa amb una matriu,
el nombre d'objectes que constitueixen un Vector
es pot estirar o escurçar a voluntat sense invertir massa esforç
de codificació: la gent de Sun
ja ha fet la feina per a nosaltres!
- La pràctica es completa amb un projecte més complex
que et mostrarà un exemple d'ús dels mètodes principals
del treball amb vectors de Java.
|
|
|
|
|
|
Vectors: |
|
|
|
|
|
Un Vector
és un objecte del paquet java.util, que
ve a ser una matriu que podem estirar o escursar a voluntat, sense invertir
massa esforç de codificació: la gent de Sun
ja ha fet la feina per a nosaltres! |
|
|
L'objecte Vector
conté, com a element bàsic, una matriu: |
|
|
|
|
|
protected Object[]
elementData;
// No és accessible al programador! |
|
|
|
|
|
|
i, a més, un munt de mètodes,
aquests sí public, per mirar, triar i remenar
els membres de la matriu elementData. |
|
|
|
|
|
Els més elementals són: |
|
|
|
|
- public Vector().
És el mètode constructor de la classe. Construeix un vector
amb capacitat inicial per a 10 objectes.
- public boolean add(Object
objecte). Afegeix l'Object objecte
a la cua del Vector. Si la capacitat s'ha
esgotat, el Vector redimensiona automàticament
la matriu elementData per tal que el nou element
hi càpiga.
- public void addElement(Object
objecte). El mateix que l'anterior, excepte que no informa de
l'èxit o fracàs de l'operació.
- public Object elementAt(int
index). Retorna l'objecte que és a la posició index
(el primer element és a l'índex 0).
- public void insertElementAt(Object
obj, int index). Insereix l'Object objecte
a la posició index. Els elements que
tenien índex més gran o igual que index
corren un lloc cap amunt.
- public Object remove(int
index). Exactament el contrari de l'anterior.
- public void removeAllElements().
Buida el Vector.
- public void setElementAt(Object
obj, int index). Posa l'Object objecte
a la posició index. L'objecte que hi
havia abans en aquesta posició es perd.
- public int size().
La quantitat d'objectes efectius que conté el Vector,
no pas la longitud de la matriu elementData!
|
|
|
La resta de mètodes els
pots trobar a la documentació
de la classe java.util.Vector. |
|
|
|
|
|
Vectors en marxa! |
|
|
|
|
 |
Crea el projecte
Vectors i, en ell, la classe FaDivisors.
De moment, pots començar amb aquest codi: |
|
|
|
|
|
import java.util.*;
/**
* La classe FaDivisors inclourà dos mètodes diferents
* per a construir la llista de divisors d'un nombre enter
*
* @author SGTI. FIE.
* @version 2004/08/10
*/
public class FaDivisors {
/**
* Definim un Vector
*/
Vector vectorEnters;
/**
* Mètode constructor per a objectes de la
classe FaDivisors.
* El vector vectorEnters de moment no té
cap objecte.
*/
public FaDivisors ( ) { //
constructor
vectorEnters=new Vector();
}
} |
|
|
|
|
|
|
Abans de continuar, paga la pena
inspeccionar el codi i entendre què hi ha escrit: |
|
|
|
|
|
- La primera línia és
Efectivament, com que la classe Vector és
del paquet java.util, propi del SDK
de Java, per poder fer servir els objectes
i els mètodes que inclou en la classe que ara estem escrivint,
primer de tot cal importar aquest paquet.
|
|
|
- Després es declara com a variable d'instància
un objecte del tipus Vector,
que designem com vectorEnters i en
diem així perquè els objectes que hi posarem
|
|
|
- I tot seguit teniu el mètode constructor: es construeix el
Vector vectorEnters:
vectorEnters=new
Vector(); |
En el mateix mètode constructor es podria omplir el vector (com
veureu més endavant) però ara de moment el deixem sense
cap objecte.
|
|
|
Com podem comprovar si anem pel
bon camí? Compilem la classe, construïm una instància
de FaDivisors i inspeccionem-la. |
|
|
|
|
|
|
|
|
|
|
|
et mostra l'única
variable d'instància que hi has definit, això
és, el Vector vectorEnters. També
el pots inspeccionar: |
|
|
|
|
|
|
|
|
|
|
|
Ara li estàs veient les
tripes al Vector vectorEnters: protected
Object[] elementData és la matriu que conté els objectes
que hi has posat i protected int elementCount
n'és el nombre. De moment tot està a zero. |
|
|
|
|
|
Segueix la inspecció:
mira ara protected Object[] elementData: |
|
|
|
|
|
|
|
|
|
|
|
La matriu protected
Object[] elementData té longitud 10 (ja hem dit que aquesta
era la dimensió que es donava per defecte a un Vector)...
però cap dels forats està ocupats per un objecte, tots estan
buits (nul). |
|
|
|
|
|
Posem objectes en un vector |
|
|
|
|
|
|
Ara ja podem anar per omplir
el vector amb la llista de divisors. Ho farem amb el mètode public
void posaDivisors (int n), que anirà col·locant successivament
en "forats" del vector els divisors del nombre enter n
que donem com a paràmetre. |
|
|
|
|
|
import java.util.*;
/**
* La classe FaDivisors inclourà dos mètodes
diferents
* per a construir la llista de divisors d'un nombre enter
*
* @author SGTI. FIE.
* @version 2004/08/10
*/
public class FaDivisors {
/**
* Un Vector que contindrà objectes
de la classe Integer.
*/
Vector vectorEnters;
/**
* Mètode constructor per a
objectes de la classe Divisors.
* Inicializa el vector vectorEnters
de moment sense cap objecte.
*/
public FaDivisors ( ) { // constructor
vectorEnters=new
Vector();
}
/**
* Mètode que afegeix al vector
els nombres que s'escauen
* @param n el nombre del qual vols
en fer la llista de
* divisors
*/
public void posaDivisors (int n) {
if
(vectorEnters==null) {
return;
}
vectorEnters.removeAllElements();
for
(int i=1;i<=n/2;i++) {
if
(n%i==0) {
vectorEnters.add(new Integer(i));
}
}
vectorEnters.add(new
Integer(n));
}
}
|
|
|
|
|
|
|
El codi del mètode es
descriu a continuació. |
|
|
|
|
|
- El mètode public void posaDivisors (int
n) comença per preguntar-se si el Vector
vectorEnters ja ha estat construït (precaució molt
recomanable!)
if
(vectorEnters==null) {
return;
} |
i en cas que no ho hagués estat (llavors serà certament
null) la instrucció return
aturaria l'execució del mètode.
- Després de la comprovació, en cas que ja estigui creat,
el buida completament per començar una nova llista de divisors...
vectorEnters.removeAllElements(); |
...no fos cas que el nostre Vector vectorEnters
ja tingués una llista de divisors d'un altre nombre; si fos així
i no tinguéssim aquesta precaució, aniríem afegint
una llista de divisors darrere d'una altra!
- Vist això, els divisors del nombre int n
que hem passat com a paràmetre es van afegint al vector amb una
estructura for
() {...}.
for
(int i=1;i<=n/2;i++) {
if
(n%i==0) {
vectorEnters.add(new Integer(i));
}
} |
Per als valors de la variable comptador i
des de l'1 fins a n/2
es comprova si són o no divisors propis de
n (el més gran d'aquests
pot ser n/2) .
Ho seran si el residu de la divisió de n
per i, donat per n%i
és 0. Per als que sí ho són,
els elements s'afegeixen a vectorEnters amb
el mètode public boolean add(Object objecte)
que és el mètode de la classe java.util.Vector
adequat per a aquest objectiu.
En acabar, afegim a la llista de divisors el mateix nombre int
n que, certament, és divisor de n.
vectorEnters.add(new
Integer(n)); |
|
|
|
És el moment de tornar
a compilar la classe. Si surt algun error... repassa que hagis escrit exactament
el codi. Altrament, fes NewFaDivisors() i tot
seguit a l'objecte que s'ha creat, activa el mètode void
posaDivisors amb el paràmetre int 20.
|
|
|
|
|
|
Si ara tornes a inspeccionar
veuràs: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
L'objecte vectorEnters
de la instància (objecte) faDiviso1 de
la classe FaDivisors té 6 llocs plens (això
ens ho diu protected int elementCount.)
|
|
|
|
|
|
Si els inspecciones podràs
veure que, efectivament, aquests 6 objectes corresponen als divisors de
20, és a dir {1, 2, 4, 5, 10, 20}. Tot seguit en tens una mostra:
l'objecte d'índex 3 té per valor 5 (te'n recordes que el primer
index és el 0?) |
|
|
|
|
|
|
|
|
|
|
|
Ara ja hem après a posar
objectes en un vector, però,... però per què no hi
ha escrit, simplement
a la línia que posa els nombres que ens interessen com a objectes
del vector?
|
|
|
|
|
|
Vegem-ho: Un vector ha de contenir objectes, és a dir, instàncies
qualssevol de classes qualssevol, derivades de la classe Object,
la qual, a Java,
és la mare de totes les classes. Però un nombre enter
(int) no és un Object,
ni tampoc ho són els nombres reals (float,
double) ni els valors booleans (boolean).
Si necessitem tractar-los com a Object, aleshores
cal que hi hagi definides classes (aquestes sí, filles de Object)
que els representin. Pels nombres enters (int),
la classe que els representa és la classe Integer.
Els mètodes bàsics de la classe Integer
són aquests:
- public Integer(int
valor). Un constructor per a construir (obvi!) l'objecte Integer
que representa el nombre enter valor.
- int intValue() .
Per a demanar (i, per tant saber!) el nombre enter que és representat
per un cert objecte Integer.
Ara ja es veu que new Integer(i) no fa més
que construir un Object de la classe Integer
que té com a valor el nombre enter i, per
poder guardar-lo al vector vectorEnters.
Passa que, a Java,
hi ha, en primera aproximació, dos tipus de dades:
- els tipus primitius: nombres
enters (byte, int),
nombres amb decimals (float, double)
i caràcters de text (char), i
- els objectes, derivats de classes.
Cal tenir en compte, però, que totes les classes deriven d'una
única classe mare: la classse Object.
Llavors, si és que necessites que, en algun punt del teu programa,
un valor de tipus primitiu sigui considerat un objecte amb
totes les de la llei, has de construir el corresponent objecte a partir
de les classes (Byte, Integer,
Float, Double, Char)
que el SDK
de Java
preveu per a això. Observa'n, a més, els noms: són
els dels tipus primitius, però en majúscula. |
|
|
|
|
|
Traiem objectes d'un vector |
|
|
|
|
|
|
Abans de passar a un projecte que globalitzarà les diferents possibilitats
del treball amb vectors, ara veurem una altra manera de construir un vector
que reculli la llista de divisors d'un nombre enter.
A diferència de l'exemple anterior ara el que farem serà
començar amb un vector amb molts objectes de la classe Integer
i en traurem els que sobrin. A la classe FaDivisors
pots afegir-hi aquest mètode:
|
|
|
|
|
|
import java.util.*;
/**
* La classe FaDivisors inclourà dos mètodes
diferents
* per a construir la llista de divisors d'un nombre enter
*
* @author SGTI. FIE.
* @version 2004/08/10
*/
public class FaDivisors {
<...codi
escrit anteriorment...> ;
/**
* Mètode que construeix un vector amb
els nombres de l'1 a l'n
* i després elimina del vector els
que no son divisors de n
* @param n el nombre del qual en vols fer
la llista de divisors
*/
public void treuNoDivisors (int n) {
if
(vectorEnters==null) {
return;
}
vectorEnters.removeAllElements();
for (int i=1;i<=n;i++) {
vectorEnters.add(new
Integer(i));
}
for
(int j=n;j>0;j--) {
if
(n%j!=0) {
vectorEnters.remove(j-1);
}
}
}
}
|
|
|
|
|
|
|
Com en l'exemple anterior, tot seguit expliquem el codi del mètode
void treuNoDivisors (int n):
- Les primeres línies coincideixen amb les del mètode
posaDivisors: ens preguntem si el Vector
vectorEnters ja ha estat construït; si no ho ha estat atuem
l'execució dle mètode i si ho ha estat deixem el vector
"en blanc":
if
(vectorEnters==null) {
return;
}
vectorEnters.removeAllElements(); |
Potser diràs: s'hagués pogut fer un mètode auxiliar
que fes aquesta tasca per tal d'evitar d'escriure codi repetit... i
és ben cert, però hem optat més per una visió
didàctica del tema. Ja tindràs temps de perfeccionar més
i més l'estructura de les teves classes de Java
i projectes.
- Tot seguit omplim el vector amb els objectes de la classe Integer
que representen els nombres de l'int 1 al
int n.
for (int i=1;i<=n;i++) {
vectorEnters.add(new
Integer(i));
} |
Ho fem, naturalment, amb una estructura for
() {...} que repetim per als nombres de l'1
al n i anem afegint successivament els objectes
corresponents, que quedaran correlativament en les posicions que corresponen
als índexs del 0 al n-1;
el nombre j correspon a l'objecte d'índex
j-1.
- I, en acabat, resseguim (amb un altre for
() {...}) tots els objectes del vector i eliminem els que
no són divisors de n, que són
els que compleixen que el residu de la divisió de n
per ells no és 0, és a dir n%j!=0..
for (int j=n;j>0;j--) {
if
(n%j!=0) {
vectorEnters.remove(j-1);
}
} |
Observa que ara comencem pel final, j=n, i
anem baixant, (j-- equival a j=j-1
en cada pas del bucle), fins que arribem al primer dels objectes.
És convenient fer-ho així perquè quan eliminem
(remove) un objecte del vector els índexs
dels posteriors a ell queden modificats convenientement. Si anem del
final cap al principi cada vegada que examinem un objecte té
l'índex que li hem asisgnat inicialment.
Observa que si j no és divisor de n
eliminem l'objecte d'índex j-1, conseqüentment
al fet que quan omplim el vector el nombre j correspon
a l'objecte d'índex j-1.
|
|
|
És el moment
que escriguis el codi indicat, compilis la classe i, quan tot funcioni,
facis NewFaDivisors() i tot seguit a l'objecte
que s'ha creat, activis el mètode
void treuNoDivisors amb el paràmetre int
20. |
|
|
|
|
|
Naturalment podràs
comprovar si inspecciones adequadament que, encara que s'hagi fet per un
mètode diferent, el Vector vectorEnters,
que té els objectes de la classe Integer
que corresponen als divisors de 20, és idèntic al que hem
comentat anteriorment. |
|
|
|
|
|
Cal reconèixer
que fer una i altra vegada l'acc |