miércoles, 25 de enero de 2012

2.1.3.- Programación en Android: Unos conceptos (V) - Arrays, strings, ámbitos


2.1.3.- Programación en Android: Unos conceptos (V) - Arrays, strings, ámbitos...

En este capítulo cerraremos la serie de "unos conceptos" (de java), no hemos arañado ni la parte superficial de Java, pero tampoco es la intención de esta guía, existen libros y recursos suficientes sobre esta materia en español, no así como de Android, que es la raiz principal de esta serie.
A medida que continuemos con la programación en Android iremos viendo a Java en más profundidad, pero para comenzar a dar nuestros primeros pasos creo que es suficiente. Así que terminaremos esta serie introductoria hablando de los arrays, los strings, y los ámbitos.


Arrays, arreglos o matrices.

Hablaremos de unos tipos de datos que son los llamados arrays (arreglos en algunos libros y matrices en otros) y que no son más que un conjunto de valores del mismo tipo.
Los arrays al igual que otros tipos de variables antes de ser utilizados tienen que ser declarados. Para declararlo hay que indicar el tipo de array que va a ser, osea el tipo de datos que va a contener, y su nombre. La forma genérica de declarar un array sería:

// forma genérica: tipo[] nombre;
// Ejemplo:
//Vamos a declarar un array de ints
int[] arrayInts;

Los [] después del tipo son obligatorios ya que son los que indican que se trata de un array. Hasta ahora sólo hemos declarado el tipo de array, pero todavía no le hemos asignado memoria para contener los elementos. En caso de que queramos acceder a cualquier elemento del array sin haberle asignado memoria el compilador nos dará un error.
Para asignar memoria a nuestro array debemos de ejemplarizarlo, y esto lo hacemos con el operador new. Veamos otro ejemplo dónde además de declarar el array lo ejemplarizamos:

// Ahora declaramos y ejemplarizamos el array en la misma línea.
// Este es un array de 5 elementos (de 0 a 4)
int[] arrayInts2=new int[5];

Despues de asignarle la memoria al array ya podemos comenzar a introducirle valores. Para referirnos a un elemento individual del array, debemos indicar el número de éste entre corchetes, de la siguiente manera:

arrayInts2[2] = 245;

En este ejemplo nos estamos refiriendo al tercer elemento del array. Ya que los arrays comienzan a contar sus elementos desde cero (0).
Debemos tener cuidado con esto ya que nos puede llevar a engaños porque si nos fijamos en la ejemplarización pusimos [5], y sí son cinco elementos pero contanto desde 0, con lo que el último sería [4]. De todas formas, podemos utilizar el método length para conocer cúal es el tamaño del array.

arrayInts[0] = arrayInts2.length;

El tipo con el que se pueden crear arrays puede ser cualquier tipo de dato legal en Java. Por ejemplo: ints, floats, string, char, objetos en general, etc.

Cuando el tipo es un objeto, entonces los elementos del array son de tipo referencia (en C++ serían punteros o referencias) a dicho objeto, cada elemento del array referenciaría un objeto de ese tipo. En este caso hay que recordar despues de reservar memoria para las referencias, también se debe hacer para cada objeto individual o en caso contrario nos dará una excepción de tipo "NullPointerException".

//Arrays de objetos
String[] arrayStrings=new String[5];
//Ahora tendríamos memoria para las 5 referencias, pero también
//debemos reservar memoria para los Strings individuales.
for (int i=0;i<arrayStrings.length;i++)
{
//Al utilizar new asignamos memoria a cada string.
arrayStrings[i]=new String ("Hola cadena"+i);
}

String, cadenas de texto.

Los objetos de tipo string contienen una secuencia de datos de tipo carácter.
Aunque en algunas referencias se indica que los objetos String son inmutables, lo cierto es que nos puede parecer lo contrario, por ejemplo el siguiente fragmento de código utiliza el método replace para cambiar la cadena de texto, y como podemos observar en la salida nos cambia dicha cadena. Cuando se refieren a que son inmutables, se refieren a que en este caso no se cambia el texto y se amplía la memoria reservada para el string, sino que se crea un nuevo objeto string con la modificación, y la otra se deja intacta. Dicho de otro modo estamos creando otra cadena de texto. Con una cadena no pasa nada, pero multiplicandolo por miles es una gran pérdida de tiempo y memoria.

//Objetos String
String cadena;
cadena = "Una cadena de texto";
System.out.println(cadena);
cadena = cadena.replace("Una cadena", "Doscientas cadenas");
System.out.println(cadena);

Si por el contrario sabemos que vamos a tener que trabajar con la cadena "on the fly", añadiendo y reemplazando carácteres, etc... lo mejor es utilizar la clase StringBuffer, que está optimizada para eso. Por ejemplo:

//Si queremos trabajar con las cadenas y modificarlas al vuelo
// es más eficiente utilizar la clase StringBuffer.
StringBuffer cadenaModificable;
//Estamos creando una string:
cadenaModificable = new StringBuffer("Una cadena modificable");
System.out.println(cadenaModificable);
//Le añadimos más texto. Pero se crea también un String:
cadenaModificable.append(". Otra String.");
System.out.println(cadenaModificable);

Hay que hacer notar que cada vez que le añadimos un texto a nuestro objeto StringBuffer entre comillas (como por ejemplo ". Otra String."), el compilador los convierte en objetos String, y aunque es más eficiente StringBuffer, se debe tener en cuenta que posiblemente genere más objetos de los que esperabamos.

No quería terminar esta seríe de introducción sin hablar de algo tan importante como los ámbitos de las variables.

Ámbitos

El alcance o ámbito determina tanto la visibilidad como la vida de las variables definidas en ese ámbito. Los ámbitos se determinan mediante la utilización de las llaves { }. Las variables que se definen dentro de un ámbito sólo están disponibles hasta que se salga de dicho ámbito. El ámbito de las variables en java difiere un poco de las de C++.
Por ejemplo, en el siguiente fragmento de código:
private static void ambitoVariable()
{
//Ejemplos de ámbitos de variables:
int unavariable = 1;
{
//Estamos en otro ámbito más "interior"
int otravariable = 2;
//Pódemos acceder a la variable del ámbito "superior"
// o el que engloba a este.
unavariable = otravariable;
{
//Y otro ámbito más "interior"
int terceravariable = 3;
//Podemos acceder a las variables de los ámbitos "superiores"
unavariable = otravariable = terceravariable;
//Aqui termina el ámbito de terceravariable
}
//Esta linea nos daría error, ya que no estamos en el ámbito de esa variable
//otravariable=terceravariable;
//Aqui termina el ámbito de otra variable
}
//Aqui solo tenemos disponible a esta variable:
unavariable = 40;
//Estas líneas dan error ya que están en otro ámbito.
//otravariable = 2;
//terceravariable = 3;
}

Los modificadores de acceso controlan el acceso a los miembros de la clase, ya que podemos tener algunas variables u objetos que pueden ser accedidos desde fuera de la clase y sin embargo tener otros que son utilizados de modo interno a dicha clase y no deberían ser utilizados externamente. Mediante los especificadores de acceso se protegen las variables y los métodos de la clase cuando son declarados. En Java existen cuatro niveles de acceso: private, protected, public y package. Veamos quién puede acceder:

Especificador
Clase
Subclase
Package
Mundo
Private
SI



Protected
SI
SI(*)
SI

Public
SI
SI
SI
SI
Package
SI

SI


En la primera columna observamos que con cualquier especificador de acceso que utilizemos la propia clase siempre tendrá acceso al miembro.
En la segunda columna se observa que en las subclases, osea las que hereden de esta clase, sólo tendran acceso a los miembros con los especificadores protected o public.
En la tercera cMiemolumna vemos como las clases del mismo paquete, tienen acceso a los miembros.
Y en la cuarta columna se indica si todas las clases, incluso las de otros paquetes tienen acceso a los miembros.
Se puede observar que el acceso más permisivo lo tenemos con el especificador public, y el más restrictivo con el especificador private.

Private: Es el nivel de acceso más restrictivo. Los miembros así definidos sólo se pueden acceder desde la clase en la que se definen.

Protected: Permite a la clase, las subclases y las demás clases en el mismo paquete acceder a los miembros. Se utiliza cuando se necesita que una subclase pueda tener acceso a los miembros, pero no las clases que no estén relacionadas. Si una clase es subclase o está en el mismo paquete que el miembro protected entonces la clase tiene acceso a dicho miembro.

Public: Todas las clases, en todos los paquetes tienen acceso a los miembros públicos de dicha clase. Ancha es Castilla, como se suele decir. Sólo se deben declarar así los miembros cuando se sepa que su acceso no dará resultados indeseados al ser utilizados por terceros.

Package: Este es el acceso que tenemos en caso de no especificar ningún modificador de acceso. Se permite a las clases del mismo paquete que se acceda a los miembros.

Cuándo hablamos de las clases, hablamos de que les podían añadir unos modificadores para indicar el tipo de acceso, vamos a recordarlos:

Public: Indica que la clase puede ser utilizada por objetos fuera del paquete actual. En caso de utilizarlo suele ser el primer elemento de la declaración.
Abstract: Declara la clase como abstracta. Las clases abstractas pueden contener métodos para los que no se ha creado la implementación. Las clases de este tipo están diseñadas para ser superclases y no pueden ejemplarizarse.
Final: Al añadir este modificador, indicamos que la clase no puede tener subclases. No se puede heredar.
No tiene mucho sentido utilizar los modificadores abstract y final juntos, ya que si no implementamos los métodos, ni dejamos que se implementen, en fin...



Se puede descargar un ejemplo de este capítulo aquí.




Ver. 1.0 – Revisión 25.1.2012

No hay comentarios:

Publicar un comentario