- José Enrique Amaro Soriano
- Android
- index_split_020.html
APÉNDICE A
ELEMENTOS DE JAVA
Este apéndice
contiene una introducción al lenguaje Java necesario para seguir
los ejemplos de este libro. Esta introducción a Java es específica
para Android. No trataremos los programas Java independientes ni
los applets. Por tanto, todos los ejemplos podrán ejecutarse como
aplicaciones Android en un emulador o en un teléfono o tablet. Esta
aproximación a Java es algo inusual. Existe una idea establecida de
que el lenguaje Java debe aprenderse antes que Android y de hecho todos los libros de Android
suponen que el lector conoce Java u otro lenguaje similar como C++.
Aunque la lógica de primero se empieza a andar y luego a correr
es correcta, lo que es desacertado en en el
presente caso es asociar a Android con correr. Aunque las aplicaciones profesionales de Android son
programas de gran complejidad, esto no impide que se puedan
escribir programas sencillos que puedan
comprenderse y que permitan aprender el lenguaje. Al aprender
Android y Java al mismo tiempo, se evita tener que asimilar
conceptos de Java que Android no soporta, por ejemplo, los gráficos
y los applets.
A.1. Programa básico de Java con
Android
Utilizaremos
el programa Eclipse para crear un nuevo proyecto de Android
llamado EjemploJava1. Un
proyecto de Android contiene un programa de Java y otros datos en
una serie de ficheros, que son utilizados por el programa o por el
sistema. Un programa de Java es una colección de
clases, contenidas en
uno o varios ficheros file1.java, file2.java,…. En Android estos ficheros java se almacenan en el
directorio src de nuestro
proyecto actual. Al crear nuestro nuevo proyecto de Android, se
crea la actividad EjemploJava1,
almacenada en el fichero EjemploJava1.java,
que se encuentra en el directorio src. Al hacer doble click sobre este fichero en el
explorador de archivos, se abre en el editor de Eclipse
y nos encontramos con el programa Java más
simple:
package es.ugr.amaro;
import
android.app.Activity;
import android.os.Bundle;
public class EjemploJava extends Activity
{
/** Called when the activity is
first created. */
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Este es el
modelo que utilizaremos como punto de partida en todos nuestros
programas Java. Examinemos su estructura:
• El
programa contiene una serie de instrucciones o sentencias. En Java
cada instrucción o sentencia debe terminar con un
punto y
coma. Se pueden escribir
varias instrucciones en una línea o una instrucción en varia
líneas. Los espacios en blanco son ignorados.
• La
primera línea package
es.ugr.amaro.ejemplojava1;
indica que esta clase pertenece al paquete es.ugr.amaro. Cada
punto en el nombre de un paquete indica un subdirectorio, por lo
que nuestro programa Java está contenido en el
directorio:
src/es/ugr/amaro/ejemplojava1
• Las dos líneas siguientes precedidas
por import indican que
este programa utiliza dos clases predefinidas en dos paquetes del
sistema Android.
import
android.app.Activity;
import
android.os.Bundle;
En este caso,
el programa importa la clase Activity del paquete android.app y la
clase Bundle del
paquete android.os. Android
contiene numerosos paquetes con miles de clases. En el editor de
Eclipse, cuando escribimos el nombre de una clase, ésta se subraya
en rojo si se requiere añadir un import, por lo que no necesitamos recordar el nombre del
paquete. Basta pulsar con el botón derecho sobre el nombre de la
clase y aparece una lista de opciones, entre ellas la de importar
el paquete. La seleccionamos y Eclipse escribirá la
instrucción import por
nosotros.
• El
programa contiene una clase llamada EjemploJava1
cuya definición abarca el bloque de código
comprendido entre la llave inicial y final:
public
class JavaEjemplo1 extends Activity {
}
Notese que la
definición de la clase no termina con punto y coma. Esto es debido
a que no se trata de una sentencia o instrucción ejecutable, sino
un tipo de definición. El
atributo public indica que la
clase es pública y puede ser utilizada externamente. La declaración
de la clase finaliza con extends Activity.
Esto significa que nuestra clase es una subclase de la clase
Activity, definida en
el paquete android.app y hereda
todas sus propiedades, además de las que nosotros le queramos
añadir. Por tanto, JavaEjemplo1 es una
extensión o una generalización de la clase Activity. Se dice que Activity es una
super-clase de JaveEjemplo1.
• La
siguente línea:
/** Called when the
activity is first created. */
es un
comentario. Los comentarios pueden abarcar varias líneas y se
delimitan por las parejas de caracteres:
/** ... */
o
también:
/* */
Las dobles
barras // comienzan un
comentario hasta el final de la línea.
• Dentro de la definición de la
clase JavaEjemplo1 encontramos la declaración de un método de la clase llamado onCreate.
@Override
public
void onCreate(Bundle savedInstanceState) {
}
Este método es
una función con un parnámetro llamado savedInstanceState de tipo Bundle. La
declaración comienza con la clave @Override, lo
que indica que se está redefiniendo o sobreescribiendo el
método onCreate
de la super-clase. El tipo de acceso del
método es public, o público, al
que se puede acceder externamente desde otro programa. El método es
de tipo void porque esta
función no devuelve ningún resultado.
• Finalmente, entre dos llaves, tenemos
la definición del método, que consiste en dos
instrucciones:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
En la pimera,
el prefijo super indica ejecutar
un método de la super-clase Activity. Por
tanto, la instrucción:
super.onCreate(savedInstanceState)
ejecuta el
método onCreate()
de Activity, aplicado
sobre el argumento savedInstanceState.
La última instrucción ejecuta el método setContentView() tomando como argumento la variable R.layout.main, que es
una referencia al fichero main.xml que contiene el layout de la interfaz de usuario que
vemos en la pantalla.
Esta es la
estructura básica de una actividad o programa de Android, que puede
considerarse un molde, o template para todos
los programas que escribiremos a continuación. Usaremos siempre el
siguiente fichero res/layout/main.xml:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ffffff"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:textColor="#000000"
android:textSize="18sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:id="@+id/textView"
/>
</LinearLayout>
El anterior
layout define un campo de texto llamado "textView" que nos permite
escribir en la pantalla. A continuación, modificaremos el programa
básico para escribir texto en la pantalla como en el siguiente
ejemplo.
package
es.amaro.ugr.ejemplojava1;
import
android.app.Activity;
import
android.os.Bundle;
import
android.widget.TextView;
public class EjemploJava1 extends
Activity {
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
textView=
(TextView)
findViewById(R.id.textView);
textView.setText(
"El
programa más básico de Java con Android " +
"escribe
un texto en la pantalla con setText.");
textView.append(
"
Así se añade más texto con append.");
textView.append("\nAsí
se escribe una segunda línea." );
}
}
Aquí se define
una variable textView
que se refiere al campo de texto y permite
modificarlo con setText ()
y añadir más texto con append
(). El resultado se ve en
la figura
A.1.

Figura A.1.
Programa básico para
escribir texto.
A.2.
Variables
Las variables
almacenan datos, que pueden ser datos primitivos (números en
distintas representaciones) o referencias a objetos (que son
conjuntos de datos). Los tipos de datos primitivos son:
int, float, double,
char, boolean, long, short y byte. Los más importantes pueden
almacenar:
• int. Un número entero entre -2,147,483,648
y +2,147,483,647.
• float. Un número con decimales entre 3.4e-38 y 3.4e+38.
• double. Un número en doble precisión entre 1.7e-308 y 1.7e+308.
• char. Un caracter UNICODE.
• boolean. Una variable lógica que vale true o false.
Otros tipos de
variables importantes son:
• String. Es una clase para almacenar cadenas de
caracteres.
• void. Se usa para describir un
método que no devuelve ningún valor.
Las variables
deben declararse e inicializarse en cualquier punto del programa.
Por ejemplo, modifiquemos el programa anterior para declarar e
inicializar algunas variables, que escribiremos en
pantalla.
public class EjemploJava1 extends Activity
{
/** Called when the
activity is first created. */
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText(
"Declaración
e inicialización de variables ");
//
declaración e inicialización de variables
int
i;
i=123;
float
x,y=1;
x=0.5123f;
double
a= 123, b=3.1416e-10;
char
caracter=‘a’;
boolean
esFalso=true;
String
cadena="Esto es una cadena";
//
escribe los valores de las variables
tv.append("\n
i="+i);
tv.append("\n
x="+x+",y="+y);
tv.append("\n
a="+a+",b="+b);
tv.append("\n
caracter="+caracter);
tv.append("\n
esFalso="+esFalso);
tv.append("\n
cadena="+cadena);
}
}
El resultado
de este programa se ve en la figura
A.2. Vemos que pueden declararse
varias variables del mismo tipo en la misma sentencia separándolas
con comas. Los valores de las variables float deben tener el
sufijo "f".

Figura A.2.
Declaración e
inicialización de variables.
A.3. Conversión de
variables
Las valores de
las variables se pueden convertir de un tipo a otro. Si la
conversión se hace a un tipo más amplio, por ejemplo de
int
a float, la conversión
se realiza implícitamente. Si, al contrario, la conversión se
realiza a un tipo más restringido, necesitamos indicarlo
explícitamente con una conversión o cast, indicando el nuevo tipo entre paréntesis pues se puede
perder información. Por ejemplo:
float a = 1.5f;
int i = (int) a;
En el
siguiente ejemplo convertimos un valor de int a float a double y
viceversa.
public class EjemploJava1 extends
Activity {
/** Called when the
activity is first created. */
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText(
"Conversión
de variables ");
// conversion
de int a float a double
int
i=125;
float
x=i;
double
d=x;
tv.append("\n\n
Conversion de int a float a double");
tv.append("\n
i="+i);
tv.append("\n
x="+x);
tv.append("\n
d="+d);
// conversion
de double a float a int
d=0.0123456789e3;
x=(float)
d;
i=(int)
x;
tv.append("\n\n
Conversion de double a float a int");
tv.append("\n
d="+d);
tv.append("\n
x="+x);
tv.append("\n
i="+i);
}
}
El resultado
de la conversión se ve en la figura
A.3

Figura A.3.
Conversión de
variables.
A.4. Operaciones con
variables
Con las
variables numéricas se pueden realizar las operaciones aritméticas
de suma, resta, multiplicación y división (+,-,*,/). También está definido el resto tras una
división (%) y el incremento y
decremento en una unidad (++, --). A continuación, tenemos un ejemplo de
utilización de estos operadores algebraicos. El resultado se ve en
la figura
A.4. Los operadores se pueden
combinar para realizar operaciones más complejas. Hay que tener
cuidado de incluir los paréntesis necesarios, si no estamos seguros
de la preferencia en que se realizan las operaciones. Por ejemplo,
la multiplicación se realiza antes que la suma, así que
x+y*z=x+(y*z). Se
pueden sumar variables de distinto tipo y el resultado es una
variable del tipo más amplio. Por ejemplo, la suma de un entero y
un float es un float. Si queremos que el resultado de una operación
se convierta a un tipo más restingido, debemos preceder la
expresión con el nuevo tipo entre paréntesis, poniendo también
entre paréntesis, si es necesario, la expresión que se está
convirtiendo. Por ejemplo i=(int)(x+y) no es lo
mismo que i=(int)x+y. En este
último caso, x se convierte a
entero antes de sumar. Ante la duda siempre es preferible escribir
los paréntesis.

Figura A.4.
Operaciones algebraicas
con variables.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("
Operaciones aritméticas\n");
int
i=1,j;
double
x=2,y=3,z;
//
suma
z=x+y;
tv.append("\n
"+x+" + "+y+" = "+z);
//
resta
z=x-y;
tv.append("\n
"+x+" - "+y+" = "+z);
//
multiplicacion
z=x
* y;
tv.append("\n
"+x+" * "+y+" = "+z);
//
division
z=x
/ y;
tv.append("\n
"+x+" / "+y+" = "+z);
//
resto
x=
74;
z
= x % y;
tv.append("\n\n
"+x+" / "+y+" da resto = "+z);
//
incremento
i++;
tv.append("\n\n
i incrementado en uno = "+i);
i--;
tv.append("\n
i decrementado en uno ="+i);
//
suma de tipos distintos
tv.append("\n\n
Operaciones con tipos distintos");
z=
x+i;
j=
(int) x+i;
tv.append("\n"+x+"+"+i+"="+z);
tv.append("\n"+x+"+"+i+"="+j);
//
operaciones más complejas
z=
(x*(y+j)/(x*x+1)-1/y)*(i-x)/y;
z
= z*z;
tv.append(
"\n\n
Resultado de operación compuesta z="+z);
}
}
A.5. Funciones
matemáticas
Las funciones
matemáticas están definidas como métodos de la clase
Math en el
paquete java.lang. Este
paquete es importado automáticamente. En el siguiente ejemplo
utilizamos algunas de las funciones más usuales y el resultado se
ve en la figura A.5.

Figura A.5.
Funciones matemáticas
en Java.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
double
x,y,z;
x=Math.PI;
tv.setText("x
= PI = "+x);
y=-1;
tv.append("\n
y = "+y);
tv.append("\n
Valor absoluto de y ="+Math.abs(y));
z=Math.sqrt(x);
tv.append("\n
Raiz cuadr. de x="+z);
z=Math.log(x);
tv.append("\n
Logaritmo de x ="+z);
z=Math.exp(x);
tv.append("\n
Exponencial(x) ="+z);
z=Math.pow(x,3);
tv.append("\n
x al cubo ="+z);
z=Math.cos(x);
tv.append("\n
coseno de x= "+z);
z=Math.sin(x);
tv.append("\n
seno de x= "+z);
z=Math.tan(x);
tv.append("\n
Tangente(x)= "+z);
z=Math.acos(y);
tv.append("\n
Arcocoseno(y)= "+z);
z=Math.asin(y);
tv.append("\n
Arcoseno(y)= "+z);
z=Math.atan(y);
tv.append("\n
Arcotangente(y)= "+z);
z=Math.max(x,y);
tv.append("\n
Maximo de x e y ="+z);
z=Math.IEEEremainder(x,
y);
tv.append("\n
El resto de x entre y es= "+z);
z=Math.toDegrees(x);
tv.append("\n
Expresado en grados x= "+z);
z=Math.toRadians(y);
tv.append("\n
Expresado en radianes y="+z);
}
}
Otros métodos
de interés son:
• random() devuelve un número aleatorio entre 0 y
1,
• los métodos de redondeo hacia
arriba ceil(), hacia
abajo floor(), que
proporcionan números double con cifras
decimales nulas,
• round() redondea
un float y lo transforma
en el int más próximo, o
redondea un double y lo
transforma en long.
El siguiente
ejemplo hace uso de estos métodos. El resultado se ve en la
figura
A.6.

Figura A.6.
Números aleatorios y
métodos de redondeo.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Números
aleatorios y métodos de redondeo");
double
x,y;
int
i;
x=2*Math.random();
tv.append(
"\n
Un número aleatorio entre 0 y 2, \n x= "+x);
y=Math.ceil(x);
tv.append("\n
ceil(x)= "+y);
y=Math.floor(x);
tv.append("\n
floor(x)= "+y);
i=(int)
Math.round(x);
tv.append("\n
round(x)= "+i);
tv.append(
"\n\n
Redondeos hasta cualquier cifra decimal");
y=Math.round(x*1.e2)/1.e2;
tv.append("\n
redondeado a la segunda cifra "+y);
y=Math.round(x*1.e3)/1.e3;
tv.append("\n
redondeado a la tercera cifra "+y);
y=Math.round(x*1.e4)/1.e4;
tv.append("\n
redondeado a la cuarta cifra "+y);
y=Math.round(x*1.e5)/1.e5;
tv.append("\n
redondeado a la quinta cifra "+y);
}
}
A.6. Bloque
if-else
Un bloque es
una serie de instrucciones entre los caracteres abrir y cerrar
llave:
{ ...
}
En Java un
bloque se procesa como si se tratara de una sóla instrucción o
sentencia. Las variables declaradas dentro de un bloque no están
definidas fuera de él.
Los bloques
if-else permiten ejecutar instrucciones dependiendo de la relación
entre los valores de ciertas variables. Esta relación se
establece mediante el uso de los operadores de comparación, que
son: igual, distinto, mayor, menor, mayor o igual, menor
o igual:
==, !=, >,
<, >=, <=
También se
pueden utilizar variables booleanas, que darán true o false si
cierta relación se verifica, por ejemplo:
float x = 1, y = 2 ;
boolean condicion = x <
y;
Los operadores
lógicos entre variables booleanas son: AND, denotado en
java:
& , &&
y
OR:
| , ||
Por
ejemplo:
boolean
condicion1,condicion2,condicion3,condicion4;
condicion3 = condicion1 &
condicion2;
condicion4 = condicion1 |
condicion2;
La diferencia
entre los operadores simples (&) o dobles (&&), es que
el simple evalúa ambas condiciones, mientras que el doble evalúa la
primera y, si es falsa, no evalúa la segunda.
En el
siguiente ejemplo demostramos el uso del bloque if-else y del uso
de variables boolean. El resultado
en la figura
A.7.

Figura A.7.
Bloques if-else y uso
de variables booleanas.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("
Bloque if-else \n");
double
x=2,y=3;
if(x==y){
tv.append("\n
"+x+" = "+y);
}
else if(x>y){
tv.append("\n
"+x+" > "+y);
}
else {
tv.append("\n
"+x+" < "+y);
}
tv.append("\n\n
Operadores booleanos");
boolean
condicion1= x>1;
boolean
condicion2 = y<5;
tv.append("\n
condicion1 es = "+condicion1);
tv.append("\n
condicion2 es = "+condicion2);
if(condicion1
& condicion2){
tv.append("\n
Las dos son true simultaneamente: " +
"\n"+x+"
> 1 y "+y+" < 10");
}
else{
tv.append("\n
Una de las dos es falsa");
}
}
}
A.7. Bucles
for
El
bucle for permite repetir
una instrucción normalmente utilizando un índice que se incrementa
en cada paso. La instrucción a repetir puede ser una
única sentencia o un bloque delimitado por llaves. Su
estructura es la siguiente:
for ( inicializacion ; condicion ;
incremento )
{
// bloque de
sentencias
sentencia1;
sentencia2;
...
}
El argumento
de for, entre
paréntesis, consta de tres sentencias separadas por un punto y
coma. En la primera se inicializa una o varias variables. La
segunda es una condición o expresión booleana. Si la condición se
verifica, se ejecutará el bloque que viene a continuación.
Finalmente se incrementa la variable. Se repite el proceso hasta
que la condición deje de verificarse. Las variables declaradas
dentro del bucle no están definidas fuera de
él.
En el
siguiente ejemplo usamos un bucle for para generar una tabla de valores de la función seno
entre 0 y 1, figura A.8. Si
intentamos escribir el valor de la variable i después del bucle, el compilador de java genera un
error: variable no definida.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Bucle
for");
double
x=10,y = 0;
for(int
i=0; i<10; i++){
y=Math.sin(i/x);
tv.append("\n
"+i+", sin(i/x)= "+y);
}
tv.append(
"\n
Fin del bucle for, i no está definida");
tv.append("\n
y= "+y);
}
}

Figura A.8.
Bucle
for.
A.8. Bucle
while
El
bucle while es similar al
bloque for, pero sólo
requiere como argumento una condición o variable booleana. El bucle
se ejecuta repetidamente hasta que la condición sea
falsa.
while( boolean )
{
// bloque de
sentencias
sentencia1;
sentencia2;
...
}
En el
siguiente ejemplo generamos una tabla de 10 números aleatorios
usando un bucle while con una variable que se va incrementando
hasta que toma el valor 10, y el bucle finaliza (figura
A.9).

Figura A.9.
Bucle
while.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Bucle
while");
int
i=0;
while(i<10){
//
variable no definida fuera del bucle
double
y=Math.random();
tv.append("\n
"+i+", random()= "+y);
i++;
}
tv.append("\n
Fin del bucle for, i="+i);
}
}
Para mayor
control del desarrollo de un bucle, pueden utilizarse además las
siguientes sentencias:
• break. Finaliza el buble.
• continue. Vuelve al comienzo del bucle.
Por ejemplo en
el siguiente programa utilizamos break y continue para
controlar la terminación de un bucle, saltando el quinto paso
(figura
A.10).

Figura A.10.
Bucle while usando
break y continue.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Bucle
while");
int
i=0;
while(true){
i++;
//
salta al principio del bucle
if(i==5)
continue;
//
finaliza el bucle
if(i==10)
break;
double
y=Math.sqrt(i);
tv.append("\n
"+i+", sqrt()= "+y);
}
tv.append("\n
Fin del bucle, i="+i);
}
}
A.9. Bloques
switch
El bloque
switch es una alternativa al bloque if-else si queremos realizar
una acción dependiendo del valor de una variable, comparándola con
una serie de casos. Después de cada caso hay que utilizar
break
para finalizar el bloque, porque todo lo que
viene a continuación se ejecuta siempre sin realizar las
comparaciones. He aquí un ejemplo de uso de switch dentro de un bloque for, cuyo resultado se ve en la figura
A.11.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Bucle
switch");
for(int
i=0;i<20;i++){
switch(i){
case
5:{
tv.append("\n
pasa por 5");
break;
}
case
10: {
tv.append("\n
tambien pasa por 10");
break;
}
case
15:{
tv.append("\n
toma el valor 15");
break;
}
default:
tv.append("\n
i= "+i);
} //
fin del bloque switch
} //
fin del bloque for
}
}

Figura A.11.
Bloque switch dentro de
un bucle for.
A.10.
Métodos
Un método es
un bloque de sentencias que se puede ejecutar repetidas veces
invocando su nombre. Los métodos pueden tener cero, uno o varios
parámetros y devolver o no un resultado de cierto tipo. Los métodos
son el análogo de las funciones o subrutinas de otros lenguajes. La
declaración de un método tiene la siguiente
estructura:
acceso resultado nombre (lista de
parámetros) {
// Bloque del método
....
return valor; // si no es
void
}
• Acceso indica si el método se puede ejecutar desde otra clase
distinta, y puede ser public, private, protected, o el tipo por defecto, si no se indica
nada.
• Resultado debe ser un tipo de dato primitivo, int, float, double,
etc., o el nombre de una clase o
void,
si el método no devuelve ningún
resultado.
• Nombre es el nombre del método.
• La
lista de parámetros, indicando tipo y nombre, separados por
comas.
En el
siguiente ejemplo definimos un método para calcular el factorial de
un número (n!). Este método lo
incluimos como método de la clase EjemploJava1 después del método onCreate, en el que hemos estado programando hasta ahora. El
método factorial es llamado
repetidas veces en un bucle desde el método onCreate. Distintos métodos de una clase pueden llamarse entre
sí. El resultado es una tabla con el factorial de los primeros 20
números, figura A.12.

Figura A.12.
Uso de un método para
calcular el factorial de un número.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Metodo
factorial");
for(int
i=0;i<20;i++){
tv.append("\n
"+i+" ! = "+factorial(i));
}
}
// metodo para
calcular el factorial de un numero
double factorial(int
n){
double
fac=1;
if
(n==0)return fac;
for (int
i=1;i<=n;i++)fac=fac*i;
return
fac;
}
}
En el
siguiente ejemplo definimos un método void para imprimir un número, que no devuelve ningún
resultado. Tiene dos argumentos: un número float y un objeto TextView, el campo de
texto donde estamos escribiendo. El resultado de imprimir varios
números en un bucle se ve en la figura
A.13.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Metodo
void para imprimir");
for(int
i=0;i<20;i++){
float
x=i*i;
print(x,tv);
}
}
// metodo para escribir un
numero en un campo de texto
void print(float x,
TextView tv){
tv.append("\n
Metodo print "+x);
}
}

Figura A.13.
Un método void para
imprimir un número.
Un ejemplo de
un método que no requiere ningún argumento es la función para
generar números aleatorios Math.random().
A.11. Clases y
objetos
Un objeto es
un conjunto de datos de distintos tipos que se referencian con una
única variable. Los objetos no sólo contienen datos sino que
también realizan acciones. Cada objeto pertenece a una
clase
y debe declararse como tal precediendo el
nombre de la variable por el nombre de la clase mediante la
sentencia:
NombreDeLaClase
variable;
Una clase es
un bloque de código con toda la información sobre los tipos de
datos que contienen sus objetos, cómo construirlos, y con métodos
para operar sobre sus datos o para realizar acciones concretas. Una
clase contiene variables de clase y métodos. Todos los métodos de
una clase tienen acceso a las variables de clase y pueden
modificarlas, a no ser que las variables se declaren
final. La estructura
de una clase es la siguiente:
acceso class Nombre
{
// variables de la
clase
variable1;
variable2;
//otras variables
...
//metodos de la
clase
metodo1 (parametros)
{
....
}
metodo2
(parametros){
...
}
// otros metodos
...
}
El
identificador de acceso de una clase sólo puede ser
public
o ninguno. Todas las sentencias de un
programa Java, excepto package e
import, deben estar
contenidas dentro de una clase. Las clases utilizadas en un
programa Java pueden ser definidas por el programador, o ser de un
paquete de las librerías de Java. Existe el convenio de que el
nombre de una clase empiece siempre por
mayúscula.
Un programa
Java es una colección de clases en uno o varios ficheros. Un
fichero puede contener varias clases, pero sólo una puede
ser public. El nombre del
fichero debe coincidir con el de la única clase public que contiene.
En el
siguiente ejemplo definimos una clase Dato del tipo
más simple, que contiene únicamente datos: un entero, un float y un
double. En la clase principal EjemploJava1
creamos un objeto de tipo
Dato usando new Dato() y
asignamos valores a sus variables o campos de clase. Para acceder a
estas variables usamos el nombre del objeto, seguido de un punto y
el nombre de la variable. La salida del programa se ve en la
figura
A.14. La clase
Dato se ha
incluido al final del fichero principal, pero podría igualmente
incluirse sola en un archivo Dato.java
en el mismo directorio, declarándola
public.

Figura A.14.
Uso de una clase para
albergar datos.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText(
"Clase
que contiene tres datos numéricos");
tv.append("\n
Se accede a las variables de clase " +
"mediante
el nombre del objeto, seguido de un " +
"punto
y el nombre de la variable");
//
declaracion de objeto Dato
Dato
miDato;
//
creación de objeto Dato;
miDato=new
Dato();
//
asignación de valores para el objeto Dato
miDato.i=1;
miDato.f=1.35f;
miDato.d=2.3e2;
tv.append("\n
miDato.i= "+miDato.i);
tv.append("\n
miDato.f = "+miDato.f);
tv.append("\n
miDato.d = "+miDato.d);
}
}
class Dato {
int i;
float f;
double
d;
}
Entre los
programadores de Java, se aconseja que las variables de clase se
declaren privadas mediante private y que no
puedan ser modificadas, ni siquiera visibles, fuera de la clase.
Esto significa que el acceso a la variable de clase mediante
objeto.variable no es posible y dará un error de compilación. Para
extraer y modificar las variables se usan exclusivamente métodos,
lo que permite controlar sus posibles valores. Para inicializar las
variables se usa también un método constructor
con el mismo nombre que la clase, que se
ejecuta al crear un nuevo objeto. El constructor debe ser
void. Puede haber
varios constructores con distintos argumentos y se ejecutará el que
corresponda.

Figura A.15.
Uso de una clase para
albergar datos, con variables de clase
privadas.
A
continuación, modificamos el ejemplo anterior ocultando los campos
de clase y usando métodos. El constructor Dato() permite inicializar los objetos al crearlos
(figura
A.15).
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText(
"Clase
que contiene tres datos numéricos");
tv.append("\n
Se accede a las variables de clase " +
"mediante
el nombre del objeto, seguido de un " +
"punto
y uno de los métodos get()");
//
declaracion de objeto Dato
Dato
miDato;
//
creación de objeto Dato;
miDato=new
Dato(1,1.35f,2.3e2);
tv.append("\n
miDato.getI()= "+miDato.getI());
tv.append("\n
miDato.getF() = "+miDato.getF());
tv.append("\n
miDato.getD() = "+miDato.getD());
miDato.setI(200);
miDato.setF(1.23456f);
miDato.setD(0.1111e-23);
tv.append(
"\n\n
Después de modificar las variables con SET:");
tv.append("\n
miDato.getI()= "+miDato.getI());
tv.append("\n
miDato.getF() = "+miDato.getF());
tv.append("\n
miDato.getD() = "+miDato.getD());
}
}
class Dato {
private int
i;
private float
f;
private double
d;
// metodo constructor de la
clase
Dato(int ivar, float fvar, double
dvar){
i=ivar;
f=fvar;
d=dvar;
}
// metodos SET para modificar las
variables
void setI(int ivar){
i=ivar;
}
void setF(float
fvar){
f=fvar;
}
void setD(double
dvar){
d=dvar;
}
// metodos GET para extraer las
variables
int getI(){
return
i;
}
float getF(){
return
f;
}
double getD(){
return
d;
}
}
En el
siguiente ejemplo creamos una clase de números complejos
llamada Complejo, que se ha
añadido al final del fichero. Esta clase contiene dos
variables a,b que almacenarán
la parte real e imaginaria, respectivamente. La clase contiene
cuatro métodos. Uno con el mismo nombre de la clase,
Complejo, que se
llama constructor de la
clase, que se ejecuta al crear un objeto de la clase, donde se
inicializan las variables. Los otros tres métodos extraen la parte
real, imaginaria y el módulo del número complejo representado por
un objeto. En este ejemplo creamos dos números complejos y
escribimos sus partes real e imaginaria. El resultado se ve en
la figura
A.16.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Clase
de números Complejos");
Complejo
c1,c2,c3;
c1=new
Complejo(1,1);
c2=new
Complejo(2,3);
//
partes real e imaginaria usando métodos
tv.append("\n\n
c1="+c1.real()+"+i"+c1.imag());
tv.append("\n
c2="+c2.real()+"+i"+c2.imag());
//
partes real e imaginaria usando variables de
clase
tv.append("\n\n
c1="+c1.a+"+i"+c1.b);
tv.append("\n
c2="+c2.a+"+i"+c2.b);
tv.append("\n\n
modulo de c1 = "+c1.modulo());
tv.append("\n
modulo de c2 = "+c2.modulo());
}
}
class Complejo {
double
a,b;
Complejo(double x,double
y){
a=x;
b=y;
}
double
real(){
return
a;
}
double
imag(){
return
b;
}
double
modulo(){
return
Math.sqrt(a*a+b*b);
}
}

Figura A.16.
Uso de la clase de
números complejos.
La instrucción
para crear el número complejo 2+3i usando esta clase es:
Complejo c = new
Complejo(2,3);
En el ejemplo
vemos que podemos acceder a las variables o a los métodos de un
objeto utilizando el nombre del objeto seguido de un punto y el
nombre de la variable, o el nombre del método. Por ejemplo, la
parte real del número anterior se puede extraer de estas dos
formas:
double
r;
r=c.real();
r=c.a;
A.12.
Sub-clases
En Java se
puede definir una subclase, que hereda las variables y métodos de
la clase original, llamada su superclase. La subclase puede
contener variables y métodos nuevos, o puede redefinir o
sobreescribir los métodos de su superclase. Para declarar una
subclase se usa la estructura:
class Subclase
extends Superclase{
}
Esta
estructura de subclase es ya familiar para nosotros, puesto que la
hemos encontrado en todos los ejemplos anteriores, al definir la
clase EjemploJava1 como una
subclase de la clase Activity.
También hemos visto que en todos los ejemplos se define el
método onCreate(),
precedido por la etiqueta
@Override. Esto indica que estamos redefiniendo,
sobreescribiéndolo, el método con el mismo nombre de la
superclase Activity.
En el
siguiente ejemplo definimos una subclase Complejo2
de la clase Complejo del ejemplo anterior. Esta subclase define nuevos
métodos para sumar, multiplicar e invertir números complejos. Las
variables y métodos de la superclase están definidos y se pueden
invocar dentro de la nueva clase usando el prefijo
this. La clase y la
superclase están aquí en el mismo fichero, pero podrían haberse
puesto en ficheros java distintos, con el mismo nombre que la clase
correspondiente.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de una subclase");
tv.append(
"\n
La clase Complejo2 extiende la clase Complejo"+
"
definiendo métodos para la suma y producto " +
"
de números complejos");
Complejo2
c1,c2,c3,c1Inv,c2Inv;
c1=
new Complejo2(1,1);
c2=
new Complejo2(2,3);
tv.append("\n
c1="+c1.real()+" + i"+c1.imag());
tv.append("\n
c2="+c2.real()+" + i"+c2.imag());
//
suma c1+c2
c3=c1.sum(c2);
tv.append("\n
suma ="+c3.real()+" + i"+c3.imag());
//
producto c1*c2
c3=c1.prod(c2);
tv.append(
"\n
producto ="+c3.real()+" + i"+c3.imag());
//
inverso 1/c1
c1Inv=c1.inv();
tv.append(
"\n
1/c1 ="+c1Inv.real()+" + i("+c1Inv.imag()+")");
//
inverso 1/c2
c2Inv=c2.inv();
tv.append(
"\n
1/c2 ="+c2Inv.real()+" + i("+c2Inv.imag()+")");
//
producto c1*1/c1
c3=c1.prod(c1Inv);
tv.append("\n
c1/c1 ="+c3.real()+" + i"+c3.imag());
//
producto c2*1/c2
c3=c2.prod(c2Inv);
tv.append("\n
c2/c2 ="+c3.real()+" + i"+c3.imag());
}
}
class Complejo2 extends
Complejo{
Complejo2(double x,double
y){
super(x,y);
}
Complejo2 sum(Complejo2
c){
double
cReal=this.real()+c.real();
double
cImag=this.imag()+c.imag();
Complejo2
result= new Complejo2(cReal,cImag);
return
result;
}
Complejo2 prod(Complejo2
c){
double
cReal=this.real()*c.real()-this.imag()*c.imag();
double
cImag=this.real()*c.imag()+this.imag()*c.real();
Complejo2
result= new Complejo2(cReal,cImag);
return
result;
}
Complejo2
inv(){
double
modulo=this.modulo();
double
cReal=this.real()/(modulo*modulo);
double
cImag=-this.imag()/(modulo*modulo);
Complejo2
result= new Complejo2(cReal,cImag);
return
result;
}
}
class Complejo
{
double
a,b;
Complejo(double x,double
y){
a=x;
b=y;
}
double
real(){
return
a;
}
double
imag(){
return
b;
}
double
modulo(){
return
Math.sqrt(a*a+b*b);
}
}
El resultado
se muestra en la figura A.17. En este
ejemplo vemos que el constructor de la subclase consiste en la
línea super(x,y), lo que
indica que se ejecute el constructor de la superclase
Complejo(x,y). La
variable super hace siempre
referencia a la superclase de la clase actual. La misma fórmula se
emplea al definir el método onCreate(), cuya
primera línea es super.onCreate(),
para ejecutar el método onCreate() de la
superclase Activity.

Figura A.17.
Uso de una subclase de
números complejos.
Obsérvese que
en los tres métodos de Complejo2
se usa la variable especial
this, para
indicar el nombre del objeto asociado a la clase actual.
Así, this.real()
sería la parte real del presente
objeto.
A.13. Variables y métodos estáticos y
finales
Una clase
puede contener variables estáticas, que deben ser declaradas como
variables de clase mediante:
static
variable;
No se pueden
definir dentro de un método. Estas variables pertenecen a la clase
y no requieren un objeto de la clase para usarlas, aunque un objeto
puede modificarlas. Para acceder a una variable estática se precede
su nombre por el nombre de la clase, como Clase.variable.
Por ejemplo, la variable Math.PI
de la clase de funciones matemáticas es
estática.
Una clase
puede contener también métodos estáticos, que no requieren un
objeto de la clase para utilizarlos. Se emplean de la misma forma
que las variables estáticas. Por ejemplo, los métodos de la clase
de funciones matemáticas Math, como Math.log(),
son estáticos.
Las variables
finales son constantes que se inicializan cuando se declaran y no
se pueden modificar. Se suelen escribir con mayúsculas. Por
ejemplo:
final double
PI=3.1416;
Una variable
final también puede declararse estática.
static final
PI=3.1416;
La
variable Math.PI
es estática y final.
Un método
también puede declararse final. Se prohibe entonces que el método
pueda ser modificado por una subclase. En cierto modo el método es
constante, como las variables finales.
En el
siguiente ejemplo definimos una clase con tres variables y un
método estáticos. Dos de las variables son final y no pueden modificarse, pero la variable
aa es
incrementada cada vez que se construye un objeto. Esta variable
vale inicialmente cero (inicializada al compilar) y puede ser
referenciada antes de que exista ningún objeto de la clase. Al
crear un nuevo objeto, con new Aa(), la variable
se incrementa en una unidad, y puede utilizarse para contar el
número de objetos de la clase que se han
creado.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv=(TextView) findViewById(R.id.textView);
tv.setText("Variables
y métodos final y/o static");
tv.append("\n
static aa="+Abc.aa);
tv.append("\n
static final BB="+Abc.BB);
tv.append("\n
static final CC="+Abc.CC);
double
x=1.5;
tv.append("\n
Funcion static f(x)="+Abc.f(x));
for
(int i=1;i<10;i++){
Abc
v1=new Abc();
v1.write(tv);
}
tv.append("\n
Fuera del bucle:");
Abc
v2=new Abc();
v2.write(tv);
Abc
v3=v2;
v3.write(tv);
}
}
class Abc{
static int
aa=0;
static final int
BB=555;
static final int
CC=777;
Abc(){
aa++;
}
void write(TextView
tv){
tv.append("\n
Variable static aa="+aa);
}
static double f(double
x){
return
BB+CC*x;
}
}
La salida de
este programa se ve en la figura
A.18. Obsérvese que el valor de
la variable estatica aa se incrementa cada
vez que se crea un objeto nuevo en el bucle, pero no al asignar la
última variable v3, puesto que no se crea ningún objeto nuevo, sólo se
asigna una referencia a un objeto que ya
existe.

Figura A.18.
Uso de variables y
métodos static.
A.14.
Arrays
Los arrays
consisten en grupos de variables que se referencian con uno o
varios índices enteros. El tamaño del array, es decir, el número de
objetos que contiene, debe especificarse al crearlo. Un array es a
su vez un objeto de una clase especial y debe crearse con la
orden new, seguida de la
clase a la que pertenencen los objetos del array, especificando su
longitud entre corchetes. Por ejemplo, para declarar un array
conteniendo 3 números enteros usamos:
int [] a;
a = new int[3];
Equivalentemente, se puede declarar un array escribiendo
los corchetes tras el nombre de la variable. Por
ejemplo:
int a[];
El array
anterior contiene tres variables enteras denotadas
a[0], a[1],
a[2]. Los contenidos del array
se denotan poniendo entre corchetes una variable entera, que cuenta
el número de orden de cada elemento, a[i]. Pero hay que tener siempre en cuenta que se empieza a
contar en cero. Es decir el primer elemento de un array es el
número cero, y si el array tiene dimensión n, su último elemento es el n-1. Un array es un objeto y length es la variable de clase donde se almacena su
longitud. Por tanto, la longitud del array anterior se
puede obtener mediante a.length.
Los contenidos
de un array se inicializan automáticamente a cero si son numéricos.
También podemos inicializar un array igualándolo a un bloque de
valores separados por comas, como:
int[] a =
{1,2,3,4,5};
En el
siguiente ejemplo ilustramos el uso de los arrays en un programa
Java. Definimos un array entero, un array double, y una
función cuyo argumento es un array. El resultado se ve en la
figura
A.19..
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv= (TextView) findViewById(R.id.textView);
tv.setText("Ejemplos
de arrays");
//
definicion de un array de longitud 3
int[]
miArray;
miArray=new
int[3];
//
obtención de la longitud del array
int
longitud=miArray.length;
tv.append("\n
Longitud del array= "+longitud);
//
escribimos los valores iniciales del array (cero)
for
(int i=0;i<3;i++){
tv.append("\n
i="+i+", miArray[i]="+miArray[i]);
miArray[i]=1+i*i;
tv.append("\n
Valor después ="+miArray[i]);
}
//
inicializacion de un array
double[]
miArray2={0,1,2,3};
tv.append("\n
miArray2=");
for
(int i=0;i<miArray2.length;i++){
tv.append("
"+i+" , ");
}
double
total=suma(miArray2);
tv.append("\n
suma="+total);
}
// suma los elementos de
un array
double suma(double[]
a){
double
s=0;
int
nsumandos=a.length;
for(int
i=0;i<nsumandos;i++){
s=
s+a[i];
}
return
s;
}
}

Figura A.19.
Uso de
arrays.
A.15. Arrays
2D
Un array de
dos dimensiones (2D) es un array de arrays. Se especifica con dos
índices entre corchetes. El primero indica la fila y el segundo la
columna. Por ejemplo un array de enteros con dos filas y tres
columnas se declara de la siguiente forma:
int[][] a;
a= new int[2][3];
y sus
elementos son variables enteras denotadas a[i][j], donde i=0,1 y
j=0,1,2.
También se
puede definir cada fila separadamente como un array de una
dimensión. Por ejemplo, en las siguientes líneas primero declaramos
un array 2D que tiene dos filas. A continuación, se declara que
cada fila es a su vez un array con tres
elementos:
int[][] a = new
int[2][];
a[0]=new int[3];
a[1]=new int[3];
Esto permite
construir arrays con número de columnas variable. Por ejemplo, la
primera fila podría contener dos elementos y la segunda cuatro, de
la siguiente forma:
int[][] a = new
int[2][];
a[0]=new int[2];
a[1]=new int[4];
El siguiente
programa Android es una demostración del uso de arrays 2D en Java,
con número de columnas fijo y variable. El resultado se puede ver
en la figura
A.20..

Figura A.20.
Uso de arrays
2D.
public class EjemploJava1 extends Activity
{
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView
tv= (TextView) findViewById(R.id.textView);
tv.setText("Ejemplos
de arrays");
//
definicion de un array bidimensional
int[][]
miArray;
miArray=new
int[3][2];
//
obtención de la longitud del array
int
filas=miArray.length;
int
columnas=miArray[0].length;
tv.append("\n
miArray \n filas = "+filas);
tv.append(",
Columnas= "+columnas);
//
inicializamos el array
for
(int i=0;i<filas;i++){
for
(int j=0;j<columnas;j++){
miArray[i][j]=10*i+j;
}
}
//
escribe el contenido del array
for
(int i=0;i<filas;i++){
tv.append("\n
fila: ");
for
(int j=0;j<columnas;j++){
tv.append("
"+miArray[i][j]+",");
}
}
//
definimos e incializamos un array
double
miArray2[][]={ {1,2,3}, {4,5,6}};
filas=miArray2.length;
columnas=miArray2[0].length;
tv.append("\n\n
miArray2:");
tv.append("\n
Filas= "+filas);
tv.append("
, Columnas = "+columnas);
//
escribe el contenido del array
for
(int i=0;i<filas;i++){
tv.append("\n
fila: ");
for
(int j=0;j<columnas;j++){
tv.append("
"+miArray2[i][j]+",");
}
}
//
array con columnas variables
double
miArray3[][]=new double[3][];
miArray3[0]=new
double[1];
miArray3[1]=new
double[2];
miArray3[2]=new
double[3];
miArray3[0][0]=0;
miArray3[1][0]=10;
miArray3[1][1]=11;
miArray3[2][0]=20;
miArray3[2][1]=21;
miArray3[2][2]=22;
tv.append("\n\n
miArray3:");
for
(int i=0;i<3;i++){
tv.append("\n
Fila: ");
for(int
j=0;j<=i;j++){
tv.append(""+miArray3[i][j]+"
, ");
}
}
double[][]
miArray4={ {1,2},{3,4,5},{6},{7,8,9,0} };
tv.append("\n\n
miArray4: ");
filas=miArray4.length;
for
(int i=0;i<filas;i++){
columnas=miArray4[i].length;
tv.append("\n
Fila:");
for(int
j=0;j<columnas;j++){
tv.append("
"+miArray4[i][j]+" , ");
}
}
}
}
A.16.
Cadenas
La
clase String está definida
en el paquete java.lang y
representa cadenas de caracteres. Una cadena o String es un objeto
de esta clase. Una String literal es un texto rodeado por comillas
dobles. Para crear un objeto String se puede usar el constructor de la clase o usar una
cadena literal, por ejemplo:
String cadena;
cadena = new String("esto es una
cadena");
cadena = "esto es una
cadena";
Para
transformar a String
una variable numérica, booleana o carácter,
se usa el método estático valueOf().
double x=1.245;
String cadena=
String.valueOf(x);
Para
concatenar cadenas se usa el operador "+".
String cadena1= "esto es
";
String cadena2= "una
cadena";
String cadena3=
cadena1+cadena2;
El operador
"+" también realiza la conversión a cadenas de otros tipos de
datos.
double x=1.256;
String cadena1=
"x="+x;
Este hecho lo
hemos utilizado repetidamente en todos los ejemplos anteriores,
pues el argumento de append() es
una String.
Java incluye
numerosos métodos para manipular cadenas
incluyendo:
• length(). La longitud de una cadena cadena1 se extrae mediante cadena1.length().
• substring(int ini,int
fin). Método para extraer una
subcadena. Se especifica la posición del primer caracter incluido y
del primer caracter no incluido. La posición del primer caracter
tiene el índice cero.
• toUpperCase()
y toLowerCase(). Conversión a mayúsculas y a
minúsculas.
• compareTo(String
cadena). Compara con otra cadena
y devuelve un entero negativo si la primera es menor que la
segunda, y positivo si ocurre lo contrario. Si son iguales devuelve
cero.
• indexOf(string
cadena). Devuelve la posición de la primera
ocurrencia de una subcadena.
• replace(char a, char
b). Reemplaza el primer caracter
por el segundo.
• trim(). Elimina espacios en blanco al principio y al
final.
• toCharArray().
Extrae los caracteres de una cadena en un
array.
El uso de
estos métodos se ilustra en el siguiente programa. La salida se
puede ver en la figura A.21..
public class EjemploJava1 extends Activity
{
TextView
tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
String
cadena1="Cadenas de caracteres";
tv.setText(cadena1);
//
constructor
String
cadena2=new String("\n Constructor de cadenas");
tv.append(cadena2);
//
Concatenacion
cadena1="\n
Concatenacion";
cadena2="
de cadenas \n";
String
cadena3=cadena1+cadena2;
tv.append(cadena3);
//
Transformacion a cadena con valueOf()
double
x=3.1416e-3;
cadena2
= String.valueOf(x);
tv.append("Transformacion
de double a cadena\n");
tv.append(cadena2);
//
conversion de String a double
cadena1="3.1416e-3";
x
= Double.parseDouble(cadena1);
x=
x*2;
tv.append("\n
Conversion de string a double\n "+x);
//
conversion de String a int
cadena1="1234";
int
i= Integer.parseInt(cadena1);
i=i*2;
tv.append("\n
Conversion de string a int\n "+i);
//
longitud de una cadena
cadena1="Granada";
int
longitud= cadena1.length();
tv.append("\n
La longitud de Granada es "+longitud);
longitud="Nueva
York".length();
tv.append(
"\n
La longitud de Nueva York es "+longitud);
//
conversion a mayusculas y minusculas
cadena1="Conversion
a mayusculas";
cadena1=cadena1.toUpperCase();
tv.append("\n"+cadena1);
cadena1="CONVERSION
A MINUSCULAS";
cadena1=cadena1.toLowerCase();
tv.append("\n"+cadena1);
//
subcadenas. Indices comienzan en cero
cadena1="Extrayendo
subcadenas";
//
desde el principio hasta el caracter decimo
cadena2=cadena1.substring(0,10);
//
desde el 11 hasta el final
cadena3=cadena1.substring(11);
tv.append("\n"+cadena2);
tv.append("\n"+cadena3);
//
comparacion de cadenas
cadena1="Granada";
cadena2="Albacete";
i=cadena1.compareTo(cadena2);
if(
i<1){
tv.append("\n"+cadena1+"
antes que "+cadena2);
}
else{
tv.append("\n"+cadena1+"
despues que "+cadena2);
}
//
búsqueda de subcadenas
cadena1="Granada";
i=cadena1.indexOf("da");
tv.append("\n
Granada contiene da en la posicion "+i);
//
reemplazar caracteres
cadena1="Granada";
cadena2=cadena1.replace(‘a’,’u’);
tv.append(
"\n
Reemplazando las aes por ues: "+cadena2);
//elimina
espacios en blanco
cadena1=
" trim
elimina blancos al inicio y
fin ";
cadena1=cadena1.trim();
tv.append("\n*"+cadena1+"*");
//
extraccion de los caracteres
cadena1="Granada";
char[]
letras=cadena1.toCharArray();
tv.append("\n
Separando los caracteres:\n");
for
(int j=0;j<letras.length;j++){
tv.append("
+ "+letras[j]);
}
}
}

Figura A.21.
Manipulación de
cadenas.
A.17. Formato
numérico
Java posee una
completa librería para manipular cadenas. En esta sección
introducimos la clase DecimalFormat
para dar formato a números decimales,
transformándolos en cadenas. Esta clase es de utilidad para mostrar
números en pantalla con una estructura de cifras determinada, o
para escribirlos en un fichero. Para ello, primero se construye un
objeto de tipo DecimalFormat:
DecimalFormat df
= new DecimalFormat(patron)
donde
patron
es una cadena indicando el número de cifras
deseado, o formato. Luego se emplea el método format() para transformar un número en una cadena con dicho
formato. Por ejemplo:
double x=1.2345;
String cadena =
df.format(x);
El número se
redondea hacia arriba. Las principales reglas para especificar el
patrón son las siguientes:
• Un
punto indica la posición del punto decimal.
• El
símbolo 0 indica un dígito o
un cero si no hay ningún dígito en esa posición. Por ejemplo, el
patrón "00.000" indica
números con tres decimales y con dos cifras como mínimo a la
izquierda del punto decimal, por ejemplo, 12.345, 01.234, 12.340,
123.450.
• El
símbolo # indica un dígito.
Si no hay ningún dígito en esa posición, no escribe nada. Por
ejemplo, el patrón "##.###" produce
números con el formato 12.345, 1.23, 123.45.
• El
símbolo E seguido de ceros se
utiliza para notación científica e indica una potencia de 10. Por
ejemplo, el patrón "0.00E00" produciría
los números 1.23E03, 0.12E10, 1.20E-01.
• Una coma indica agrupación de cifras
con un separador, Por ejemplo, el patron ",000" agrupa por miles, como en 12,000.
• Con un punto y coma se puede
especificar un símbolo alternativo al signo menos de los números
negativos, en lugar de un guión.
Por defecto se
utiliza la notación "local" que generalmente consiste en que el
punto decimal es una coma y el separador de cifras es un punto.
Para modificar el separador es necesario especificar un
objeto DecimalFormatSymbols,
que define los separadores, al definir el formato. Por ejemplo,
para que el punto decimal se escriba siempre con un
punto:
DecimalFormatSymbols symbols= new
DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator(‘.’);
df= new
DecimalFormat(".###",symbols);
El
objeto symbols lleva los
símbolos locales de Estados Unidos, pero hemos modificado su
separador decimal con setDecimalSeparator().
En el
siguiente programa mostramos varios ejemplos de formato. El
resultado se puede ver en la figura
A.22..
import
java.text.DecimalFormat;
import
java.text.DecimalFormatSymbols;
import java.util.Locale;
import
android.app.Activity;
import android.os.Bundle;
import
android.widget.TextView;
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("DecimalFormat");
double
x,y,z;
x=12345.6789;
tv.append("\n
Sin formato x="+x);
DecimalFormat
df1;
df1=
new DecimalFormat(".#");
tv.append("\n
Una cifra decimal: "+df1.format(x));
df1=
new DecimalFormat(".##");
tv.append("\n
Dos cifras decimales: "+df1.format(x));
df1=
new DecimalFormat(".###");
tv.append(
"\n
Tres cifras decimales: "+df1.format(x));
df1=
new DecimalFormat(",###.##");
tv.append("\n
Agrupar por miles: "+df1.format(x));
DecimalFormatSymbols
symbols =
new
DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator(‘.’);
df1=
new DecimalFormat(".###",symbols);
tv.append("\n\n
Punto decimal = ."+df1.format(x));
y=1.234;
z=-1.234;
tv.append(
"\n\n
Rellenar con ceros a derecha e izquierda:");
tv.append("\n
sin formato y="+y);
tv.append("\n
sin formato z="+z);
//
El ; permite definir el simbolo del signo menos
df1=
new DecimalFormat("00.0000;menos",symbols);
tv.append("\n
"+df1.format(y));
tv.append("\n
"+df1.format(z));
tv.append("\n\n
Notación científica");
df1=
new DecimalFormat("0E0",symbols);
tv.append("\n
"+df1.format(y));
df1=
new DecimalFormat("0.0E00",symbols);
tv.append("\n
"+df1.format(y));
df1=
new DecimalFormat("00.00##E00",symbols);
tv.append("\n
"+df1.format(y));
df1=
new DecimalFormat(".00E0",symbols);
tv.append("\n
"+df1.format(y));
}
}

Figura A.22.
Uso de la clase
DecimalFormat para dar formato a los
números.
A.18. Manejo de
Excepciones
Cuando en la
ejecución de un programa se produce un error, ésta se detiene. Cada
error suele producir un mensaje o excepción, que permite determinar
el problema. Con el manejo de excepciones podemos evitar errores y
que el programa siga ejecutándose. Para manejar una excepción se
usa un bloque try-catch. El código
donde se puede producir un error debe estar en el bloque
try. Si el error se
produce, se lanza una excepción y se ejecuta el código del
bloque catch, que es el que
recoge la excepcion. Opcionalmente se puede incluir un
bloque finally, que se
ejecuta en todo caso, se produzca la excepción o
no.
try {
// codigo que arroja la
excepcion
}
catch (Exception e){
// codigo que recoge la
excepcion
}
finally {
// codigo que se ejecuta
siempre
}
La
instrucción catch requiere un
parámetro e, que es un objeto
de tipo Exception o una de
sus subclases, que lleva la información del tipo de error
producido. En el siguiente programa demostramos el manejo de
excepciones forzando dos errores típicos: intentar acceder a
índices de un array que no existen, lo que arroja una excepción del
tipo ArrayIndexOutOfBoundException, y acceder a índices de una cadena que tampoco existen,
lo que arroja una excepción de tipo StringIndexOutOfBoundException. El tipo de excepción recogido se escribe en pantalla,
ver figura
A.23..
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Excepciones\n");
double[]
v =new double[10];
double
x=-1;
try
{
x=v[10];
}
catch(Exception e){
tv.append("\n\n
Excepcion encontrada: "+e);
tv.append(
"\n\n
Se ha intentado acceder al indice 10 "
+"del
array v[10]");
}
finally{
tv.append("\n
x="+x);
}
String
cadena="abcdefg";
try{
tv.append("\n"+cadena.substring(15,20));
}
catch(Exception e){
tv.append("\n\n
Excepción encontrada: "+e);
tv.append("\n\n
Se ha intentado acceder " +
"a
la posicion 15 de "+cadena);
}
}
}

Figura A.23.
Uso de bloques
try-catch para recoger excepciones.
Finalmente,
indiquemos que un método puede arrojar una excepción y ésta ser
declarada mediante la etiqueta throws, por ejemplo:
public metodo throws Excepcion
{
...
throw
e;
}
En el caso en
que se produzca la excepción, el método debe arrojarla mediante la
instrucción throw e.
A.19.
Interfaces
En Java un
método no puede ser el argumento de otro método. Por ejemplo, si
escribimos un método para calcular el mínimo de una función
F(x), el nombre de la
función debe conocerse de antemano. Si queremos minimizar varias
funciones distintas, esto podría ser un problema. Las interfaces
resuelven este problema, definiendo métodos
vacíos, que se pueden
implementar posteriormente por distintas clases. Así una clase
podría contener la función a minimizar y podríamos pasarle un
objeto de esa clase al método minimizador. Una interfaz se define
similarmente a una clase, sólo que sus métodos sólo están
declarados, es decir, no están implementados. Por lo tanto, las
interfaces no son clases y, por tanto, no se pueden instanciar
objetos de una interfaz, sino de una clase que implemente la
interfaz.
Por ejemplo,
para definir una interfaz que lleva una función,
escribiríamos:
interface Funcion{
double
f(double x);
}
Aquí, la
función f(x) está declarada,
pero no está implementada. Una clase que implementa esta interfaz
podría ser la siguiente:
class Funcion1 implements
Funcion{
public
double f(double x){
return
1+x+2*x*x;
}
}
y un método
que utiliza la interfaz
sería:
double evalua(double x, Funcion
portador){
double
valor=portador.f(x);
return
valor;
}
Nótese que
aquí el argumento no es un objeto de la clase Funcion, sino de
una clase que implemente dicha interfaz.
El siguiente
ejemplo es un programa completo donde se implementa la interfaz
anterior tres veces, con tres funciones distintas, que se evalúan
en un punto y se muestra el resultado (ver figura
A.24.).
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de interfaz " +
"\n\n
Se implementan tres funciones distintas");
double
a=0.5;
class
Funcion1 implements Funcion{
public
double f(double x){
return
1+x+2*x*x;
}
}
Funcion1
miF1 = new Funcion1();
double
valor=evalua(a, miF1);
tv.append("\n\n
Valor de miF1 = "+ valor);
class
Funcion2 implements Funcion{
public
double f(double x){
return
1/(1+2*x*x);
}
}
Funcion2
miF2 = new Funcion2();
valor=evalua(a,
miF2);
tv.append("\n\n
Valor de miF2 = "+ valor);
class
Funcion3 implements Funcion{
public
double f(double x){
return
Math.atan(x);
}
}
Funcion3
miF3 = new Funcion3();
valor=evalua(a,
miF3);
tv.append("\n\n
Valor de miF3 = "+ valor);
}
// metodo para evaluar una
funcion
// proporcionada en la
interfaz Funcion
double evalua(double x,
Funcion portador){
double
valor=portador.f(x);
return
valor;
}
}
//
interfaz que lleva una funcion
interface Funcion{
double f(double
x);
}
double evalua(double x, Funcion
portador){
double
valor=portador.f(x);
return
valor;
}
}
//
interfaz que lleva una funcion
interface Funcion{
double f(double
x);
}

Figura A.24.
Uso de una interfaz
para evaluar distintas funciones en un
método.
Otro ejemplo
del uso de interfaces es el siguiente. Trabajando con arrays 2D o
matrices encontramos a menudo bloques comunes del
tipo:
for (int
i=0;i<miArray.length;i++){
for(int
j=0;j<miArray[i].length;j++){
//
instrucciones
...
}
}
El bloque
común del doble bucle podría pasarse a un método
recorreArray(), cuyo
argumento serían las instrucciones a realizar. Esto puede hacerse
con una interfaz con un método manipula, como en el siguiente programa. La interfaz,
Manipulador, está
implementada por dos clases y los objetos de esas clases se pasan
al método recorreArray()que
contiene el bucle. El resultado se ve en la figura
A.25..

Figura A.25.
Uso de una interfaz
para manipular matrices.
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de interfaz");
//
array bidimensional
double[][]
miArray;
miArray=new
double[4][3];
class
Mani1 implements Manipulador{
public
void manipula(double[][] a,int i, int j){
a[i][j]=10*i+j;
}
}
Mani1
m1= new Mani1();
recorreArray(miArray,m1);
class
Mani2 implements Manipulador{
public
void manipula(double[][] a,int i, int j){
tv.append("\n
a("+i+","+j+") = "+a[i][j]);
}
}
Mani2
m2= new Mani2();
recorreArray(miArray,m2);
}
// metodo para realizar
acciones sobre un array
// usando la interfaz
Manipulador
void
recorreArray(double[][] miArray, Manipulador m){
for (int
i=0;i<miArray.length;i++){
for(int
j=0;j<miArray[i].length;j++){
m.manipula(miArray,i,j);
}
}
}
}
// interfaz para manipular un
array
interface
Manipulador{
void
manipula(double[][] a,int i,int j);
}
Las clases
internas Mani1 y
Mani2
que implementan la interfaz
Manipulador
son ejemplos de clases
locales, que sólo son visibles
dentro de un bloque de código. En este caso, sólo se necesita
instanciar un objeto de estas clases, por lo que esta
implementación se podría haber hecho utilizando clases anónimas,
tratadas en la siguiente sección.
A.20. Clases
anónimas
Cuando sólo se
necesita un objeto de la clase, por ejemplo para implementar una
interfaz, no es realmente necesario definir una clase completa. Se
puede utilizar una clase anónima, es decir, que no tiene nombre,
instanciando directamente un objeto de la clase. Por
ejemplo:
Interfaz inter= new
Interfaz(){
// implementacion
...
};
Nótese que
aquí no se está creando un objeto de la clase Interfaz, porque las interfaces no son clases, sino que se está
creando un objeto de una clase anónima que no tiene nombre y que
implementa la interfaz.
En el
siguiente programa implementamos la interfaz Funcion de la sección anterior usando clases anónimas, el
resultado es exactamente el mismo de la figura
A.24.
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de interfaz " +
"\n\n
Se implementan tres funciones distintas");
double
a=0.5;
Funcion
miF1= new Funcion(){
public
double f(double x){
return
1+x+2*x*x;
}
};
double
valor=evalua(a, miF1);
tv.append("\n\n
Valor de miF1 = "+ valor);
Funcion
miF2 = new Funcion(){
public
double f(double x){
return
1/(1+2*x*x);
}
};
valor=evalua(a,
miF2);
tv.append("\n\n
Valor de miF2 = "+ valor);
Funcion
miF3 = new Funcion(){
public
double f(double x){
return
Math.atan(x);
}
};
valor=evalua(a,
miF3);
tv.append("\n\n
Valor de miF3 = "+ valor);
}
// metodo para evaluar una
funcion
// proporcionada en la
interfaz Funcion
double evalua(double x, Funcion
portador){
double
valor=portador.f(x);
return
valor;
}
}
// interfaz que lleva una
funcion
interface Funcion{
double f(double
x);
}
Como
descubrimos al examinar este ejemplo, en realidad tampoco es
necesario darle nombre a los objetos miF1, miF2, miF3
de la clase anónima que implementa la
interfaz Funcion, sino que
bastaría incluir su definición directamente como argumento del
método evalua(), es
decir:
double valor=evalua(a, new
Funcion(){
public
double f(double x){
return
1+x+2*x*x;
}
});
Obtenemos,
entonces, la siguiente versión equivalente del mismo programa que
ilustra las posibilidades que ofrece el lenguaje Java para definir
un método, dentro del argumento de otro método.
public class EjemploJava1 extends Activity
{
TextView tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de interfaz " +
"\n\n
Se implementan tres funciones distintas");
double
a=0.5;
double
valor=evalua(a, new Funcion(){
public
double f(double x){
return
1+x+2*x*x;
}
});
tv.append("\n\n
Valor de miF1 = "+ valor);
valor=evalua(a,
new Funcion(){
public
double f(double x){
return
1/(1+2*x*x);
}
});
tv.append("\n\n
Valor de miF2 = "+ valor);
valor=evalua(a,
new Funcion(){
public
double f(double x){
return
Math.atan(x);
}
});
tv.append("\n\n
Valor de miF3 = "+ valor);
}
// metodo para evaluar una
funcion
// proporcionada en la
interfaz Funcion
double evalua(double x, Funcion
portador){
double
valor=portador.f(x);
return
valor;
}
}
// interfaz que lleva una
funcion
interface
Funcion{
double f(double
x);
}
Aunque esta
notación es compacta y es utilizada por muchos programadores,
implementar una interfaz con una clase anónima dentro del argumento
de un método puede resultar confuso para el principiante, pues el
código resulta más difícil de entender. Sólo con la práctica se
llega a dominar esta técnica. Para comenzar se aconseja implementar
explícitamente las interfaces con clases no anónimas. La utilidad
de la clase anónima surgirá por sí sola.
Para terminar
esta discusión, el siguiente ejemplo muestra la versión del
programa de la figura A.25. implementado con clases anónimas.
public class EjemploJava1 extends Activity
{
TextView
tv;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=
(TextView) findViewById(R.id.textView);
tv.setText("Ejemplo
de interfaz");
//
array bidimensional
double[][]
miArray;
miArray=new
double[4][3];
//
Llamada al método con segundo argumento un objeto
//
de una clase anónima implementando una interfaz
recorreArray(miArray,new
Manipulador(){
public
void manipula(double[][] a, int i, int j) {
a[i][j]=10*i+j;
}
});
recorreArray(miArray,new
Manipulador(){
public
void manipula(double[][] a,int i, int j){
tv.append("\n
a("+i+","+j+") = "+a[i][j]);
}
});
}
// metodo para realizar
acciones sobre un array
// usando la interfaz
Manipulador
void recorreArray(double[][]
miArray, Manipulador m){
for (int
i=0;i<miArray.length;i++){
for(int
j=0;j<miArray[i].length;j++){
m.manipula(miArray,i,j);
}
}
}
}
// interfaz para manipular un
array
interface
Manipulador{
void
manipula(double[][] a,int i,int j);
}
A.21. Otras características de
Java
A.21.1.
Paquetes
En Java las
clases se agrupan en paquetes, especificados en la primera línea
del fichero:
package
es.ugr.amaro;
Esto indica
que el fichero .class, obtenido al compilar el fichero .java, está
localizado en el subdirectorio es/ugr/amaro. Todas
las clases del mismo paquete están en el mismo directorio. Para
evitar problemas, se aconseja utilizar nombres únicos para los
paquetes, como un nombre de dominio o de correo
electrónico. Para que una clase pueda utilizar otra
clase definida en otro paquete se debe especificar ésta con la
orden import al principio
del fichero. Por ejemplo, para usar la clase EjemploJava1
del paquete es.ugr.amaro,
escribiríamos:
import
es.ugr.amaro.EjemploJava1;
Se pueden
importar todas las clase de un paquete escribiendo un
asterisco:
import
es.ugr.amaro.*
A.21.2. Clases
públicas
Por defecto,
las clases son privadas y sólo son accesibles a las otras clases de
su mismo paquete. Si queremos que una clase sea pública y pueda ser
importada por clases en otros paquetes, debemos declararla
como public. Por
ejemplo:
public class
EjemploJava1{
...
}
A.21.3. Privilegios de acceso de los
métodos y variables
Aunque una
clase sea pública, sus métodos y variables tienen su propio tipo de
acceso, que puede ser de cuatro tipos: public, protected,
private, o el tipo por defecto,
si no se especifica nada. La diferencia está en el tipo de clases
que pueden acceder a ellos.
• public: es el tipo menos restrictivo, permitiendo acceso a
todas las clases. Es decir, si un método es public, puede invocarse
desde cualquier clase de cualquier paquete.
• protected: no permite el acceso a las clases de otro paquete, a
no ser que sean sub-clases de la clase que contiene el método o
variable.
• tipo por
defecto: si no se especifica
nada, no permite el acceso a las clases de otro paquete. Dicho de
otro modo, los métodos no pueden ser ejecutados por clases de otro
paquete. Si queremos que lo sean, deben ser declarados
públicos.
• private: es el tipo más rectictivo. No es accesible ni siquiera
a las clases del mismo paquete. Sólo lo puede ejecutar la clase que
lo contiene.
A.21.4. Clases y métodos
abstractos
Una clase
abstracta se declara precediéndola del comando abstract. Las clases abstractas son similares a las interfaces,
conteniendo lo que se denomina métodos abstractos, precedidos
también de la palabra abstract, y que sólo
están declarados, pero no implementados. Las clases abstractas se
diferencian de las interfaces en que también pueden contener
métodos concretos, es decir, implementados. No se puede crear un
objeto de una clase abstracta, sino sólo de una de sus subclases
que implemente todos sus métodos abstractos.