|
Vectors, arraylists, conversió
(casting)... |
|
|
|
Més sofisticat: vectors i
arraylists |
|
|
|
Una matriu (un array)
és, en realitat, un constructe molt primitiu,fins i tot massa.
Manipular una matriu més enllà
de posar-hi elements i fer-hi referència
pot exigir un munt de codi, no sempre prou eficient
i segur si el programador no és
un excel·lent coneixedor de tots els racons i del funcionament
de la Màquina Virtual.
Com a solució a això el paquet
(package)
java.util proporciona dues classes
que contenen una bona col·lecció de mètodes
que, en essència, no són més que manipulacions
sofisticades de matrius unidimensionals.
Les dues classes són:
- java.util.Vector
- java.util.ArrayList
|
|
Vegem què aporten aquestes
dues classes:
- Ambdues classes
guarden els objectes a la variable
Object[] elementData, és
a dir, en una matriu d'objectes
de la classe Object.
Però aquesta variable és protected,no
accessible a mètodes
d'altres classes
i, per tant, invisible al programador.
- El fet que elementData
sigui del tipus Object
(la mare de totes les classes!)
implica que, en un vector
o en un arraylist,
hi podem enmagatzemar objectes de tipus
diferents els uns dels altres; tots ells hi
queden guardats com a Object.
- A diferència de les matrius
(arrays) que, a
l' inicialitzar-les,
cal establir ja quina serà la seva longitud,
la seva capacitat,
la qual restarà inamovible, tant els vectors
com els arraylists tenen
capacitat variable:
això vol dir que si requerim guardar-hi un nou objecte
quan la matriu elementData
ja es plena, la pròpia classe,
sense intervenció de codi extern, redimensiona la matriu
elementData per tal de
rebre aquest nou objecte.
- Ambdues classes
contenen el mètode
int size(), el qual ens
retorna, no pas la longitud
de la matriu
elementData, sinó
el nombre d'objectes
efectius que guarda.
- Ambdues classes
contenen mètodes
per a insertar-hi objectes,
per poder saber si determinat objecte
hi és o no, per buidar-les, etc. Consulteu la documentació
de les classes
java.util.Vector i java.util.ArrayList.
- El comportament de vectors
i arraylists
és diferent quan han d'incrementar la seva capacitat: per defecte,
un vector que
ha de augmentar la seva capacitat, la duplica. En
canvi, un arraylist que
hagi d'augmentar la seva capacitat només la fa créixer
en un 50%. D'altra banda, en un dels mètodes
constructors de la classe
dels vectors,
public Vector(int initialCapacity,int capacityIncrement)
hom pot fixar un increment de capacitat diferent del 100% de defecte.
Aquesta possibilitat no hi és en els arraylists.
Com ja es pot comprendre, l'operació d'augmentar
la capacitat d'un vector
o d'un arraylist consumeix
temps, cosa que el programador ha de tenir en compte.
- La diferència fonamental entre vectors
i arraylists és
que tots els mètodes
capaços de canviar el contingut d'un
vector, de referir-se
a la quantitat d'elements o a la seva ordenació, són synchronized
mentre que els corresponents dels arraylists
no ho són. Això vol dir que els mètodes
de la classe
java.util.Vector són
segurs quant a "atacs"
d'altres fils
(threads,
vegeu les pràctiques 1
i 2
del mòdul 7): cap altre fil
(thread)
pot actuar sobre el vector
mentre s'està executant algun d'aquests mètodes!
En canvi, la manipulació directa de matrius
o l'execució de mètodes de la
classe java.util.ArrayList
són, en aquest sentit, ben insegurs.
Però es paga un preu: els mètodes
synchronized són
un pèl més lents que els que no ho són.
|
 |
El programa següent (Projecte
Vectors "Empty
Project", fitxer Vectors.java)
il·lustra l'ús de vectors: |
|
|
|
import java.util.*; //
Importació del paquet java.util, on hi ha
//
la classe Vector
class Vectors {
Vector vector; //
Declaració d'un objecte de la classe
//
java.util.Vector
public static void main (String[] args)
{
Vectors mainApp=new
Vectors(); // Es crea l'objecte mainApp
//
fill de la classe Vectors.
//
Això es fa així per tal
// de
poder cridar variables
//
i mètodes sense la
//
clàusula "static".
mainApp.vector=new
Vector(); // Construcció
efectiva de
//
l'objecte vector, cosa que
//
vol dir reservar-li l'espai
//
corresponent a la memòria
mainApp.omple();
// Crida al mètode void omple()
mainApp.mostraElVector();
// Crida al mètode
//
void mostraElVector()
}
void omple () { //
Addició d'objectes diversos al vector
vector.add(new Tipus_1("u"));
vector.add(new Tipus_1("dos"));
vector.add(new Tipus_2("tres",null));
vector.add(new Tipus_1("quatre"));
String[] paraules={"Pedra","Tisora","Paper"};
vector.add(new Tipus_2("cinc",paraules));
vector.add(new Tipus_1("sis"));
vector.add(new Double(Math.PI));
}
void mostraElVector () { //
"Publicació" a la sortida stàndard
//
del sistema del contingut del vector
System.out.println("El
vector conte "+ // Nombre d'elements
vector.size()+
// que
conté el
"
elements"); //
vector
System.out.println("El
vector te "+ //
Nombre d'elements
"capacitat per a "+ // que
pot contenir
vector.capacity()+ //
el vector. Si la
"
elements"); //
capacitat se
//
sobrepassa, el
//
vector augmenta
//
la seva capacitat
//
automàticament.
int ind=0;
for(Enumeration
enum=vector.elements(); // Obtenció
enum.hasMoreElements();)
{ //
d'un objecte
//
java.util.Enumeration
//
que conté la llista
//
dels objectes que hi
//
ha al vector
Object
obj=enum.nextElement(); // Referència
a un
//
objecte determinat
//
com a instància de
//
java.lang.Object
System.out.print((ind++)+".
");
if
(obj instanceof Tipus_1) { // Selecció
del
//
tipus d'objecte
//
mitjançant
//
l'operador
//
"instanceof"
Tipus_1
t_1=(Tipus_1)obj; // Casting
//
imprescindible!
t_1.explicoQuiSoc();
}
else if (obj instanceof Tipus_2) {
Tipus_2
t_2=(Tipus_2)obj; // Casting
//
imprescindible!
t_2.explicoQuiSoc();
}
else if (obj instanceof Double) {
Double
db=(Double)obj; // Casting
//
imprescindible!
System.out.println(db.doubleValue());
}
}
}
}
class Tipus_1 {
String nom; //
Variable de classe
public Tipus_1 (String nm) { //
Constructor
nom=nm;
}
public void explicoQuiSoc () {
System.out.println("Soc
"+nom+
", un objecte fill de la classe Tipus_1"
);
}
}
class Tipus_2 {
String nom; //
Variable de classe
String[] paraules; //
Variable de classe
public Tipus_2 (String nm,String[] prls)
{ // Constructor
nom=nm;
paraules=prls;
}
public void explicoQuiSoc () {
System.out.println("Soc
"+nom+
",
un objecte fill de la classe Tipus_2"
);
if
(paraules!=null) {
int
quantes=paraules.length; // Quantes
paraules
//
guardo?
for
(int i=0;i<quantes;i++) {
System.out.println(paraules[i]);
}
}
else {
System.out.println("No
guardo cap paraula...");
}
}
}
|
|
|
|
 |
Ara cal fixar-se en aquests punts:
- Com que farem servir instàncies
de les classes
java.util.Vector i java.util.Enumeration,
cal importar el paquet (package)
java.util.
- Els objectes que posem a dintre del vector
mitjançant el mètode de la classe
java.util.Vector, public
boolean add(Object obj) (no fem cas del resultat
true o false)
hi entren com a instàncies de
la classe java.lang.Object,
que és la mare de totes les
classes. Quan els haguem de recuperar, amb
algun dels mètodes de
la classe java.util.Vector,
- public Object elementAt(int index)
- public Enumeration elements()
- public Object firstElement()
- public Object get(int index)
- public Object lastElement()
- public Object remove(int index)
- public Object[] toArray()
els obtindrem també com a instàncies
de la classe java.lang.Object,
la qual no conté pas el mètode
void explicoQuiSoc()! que,
a l'exemple, cridem tot just a continuació. Observeu com, mitjançant
l'ús de l'operador instanceof
if (obj instanceof Tipus_1) { ... |
ens assegurem que obj
és una instància
d'una certa classe
i com, després, obtenim l'objecte
t_1 com a instància
efectiva d'aquesta classe
per tal de poder cridar ja als seus mètodes:
Tipus_1 t_1=(Tipus_1)obj; |
La conversió
anterior (casting)
és d'us comú en el maneig de
matrius,
vectors i arraylists.
Naturalment, ja podeu pensar que la conversió
(casting)
només funciona si a la sentència:
Tipus_1 t_1=(Tipus_1)obj; |
l'objecte obj
és, efectivament, una instància
de la classe
Tipus_1. Llavors,
t_1 és l'objecte
obj, i Java
el considera com a instància
de la classe
Tipus_1. La conversió
(casting)
inversa, com és lògic, és innecessària:
si la classe Tipus_1
deriva de la
classe Tipus_2
(filla, neta, besneta, etc...), llavors tots els
objectes que
siguin instàncies de
Tipus_1 són, automàticament,
instàncies de Tipus_2.
- Resulta molt convenient recuperar les referències
als objectes continguts en un vector
com a una instància
de la classe java.util.Enumeration.
Això es fa mitjançant el
mètode de la classe
java.util.Vector, public
Enumeration elements(). Amb el mètode
de la classe java.util.Enumeration,
public boolean hasMoreElements(),
podem arar recuperant-ne les referències successivament, tal
com es fa en l'estructura for
(... de l'exemple:
for(Enumeration enum=vector.elements();enum.hasMoreElements();)
{
Object obj=enum.nextElement();
...
...
...
}
|
|
|
|
|
|
|
|
 |
|
|
|
|