% Activate the following line by filling in the right side. If for example the name of the root file is Main.tex, write
% ...root = Main.tex if the chapter file is in the same directory, and ...root = ../Main.tex if the chapter is in a subdirectory.
 
%!TEX root =  ../notas_java.tex

\chapter[Datos y Expresiones]{Datos y Expresiones}
	
\section{Tipos de datos en java (primitivos, Clases, Interfaces, Enumeraciones)}

En nuestro primer ejemplo escribíamos un texto en pantalla, pero este texto estaba prefijado dentro de nuestro programa.

Esto no es lo habitual: normalmente los datos que maneje nuestro programa serán el resultado de alguna operación matemática o de cualquier otro tipo. Por eso, necesitaremos un espacio en el que ir almacenando valores temporales y resultados.

En casi cualquier lenguaje de programación podremos reservar esos espacios, y asignarles un nombre con el que acceder a ellos.  Esto es lo que se conoce como variables.

Por ejemplo, si queremos que el usuario introduzca dos números y el ordenador calcule la suma de ambos números y la muestre en pantalla, necesitaríamos el espacio para almacenar al menos esos dos números iniciales (en principio, para la suma no sería imprescindible, porque podemos mostrarla en pantalla nada más calcularla, sin almacenarla previamente en ningún sitio).  Los pasos a dar serían los siguientes:

 

    Pedir al usuario que introduzca un número.
    Almacenar ese valor que introduzca el usuario (por ejemplo, en un espacio de memoria al que podríamos asignar el nombre primerNumero).
    Pedir al usuario que introduzca otro número.
    Almacenar el nuevo valor (por ejemplo, en otro espacio de memoria llamado segundoNumero).
    Mostrar en pantalla el resultado de sumar primerNumero y segundoNumero.

Pues bien, en este programa estaríamos empleando dos variables llamadas primerNumero y segundoNumero. Cada una de ellas sería un espacio de memoria capaz de almacenar un número.

El espacio de memoria que hace falta reservar será distinto según la precisión que necesitemos para ese número, o según lo grande que pueda llegar a ser dicho número. Por eso, tenemos disponibles diferentes tipos de variables.

Por ejemplo, si vamos a manejar números sin decimales (números enteros) de como máximo 9 cifras, nos interesaría el tipo llamado int (abreviatura de integer, que es entero en inglés). Este tipo de datos consume un espacio de memoria de 4 bytes (1 Mb es cerca de 1 millón de bytes). Si no necesitamos guardar datos tan grandes (por ejemplo, si nuestros datos va a ser números inferiores a 1.000), podemos emplear el tipo de datos llamado short (entero corto).

Los tipos de datos numéricos disponibles en Java son los siguientes:

\begin{center}
\begin{tabular}{|c|c|c|c|c|}
\hline
Nombre &  Valor min. & Valor max. & Precisión & Ocupa \\
\hline
byte & -128 & 127 & - & 1 byte \\
short & -32,768 & 32,767 & - & 2 bytes \\
int & -2,147,483,648 & 2,147,483.647 & - & 4 bytes\\
long & -9,223,372,03,.854,775.808 & 9,223,372,036,854,775.807 & - & 8 bytes\\
float & 1.401298E-45 & 3.402823E38 & 6-7 cifras & 4 bytes\\
double & 4.94065645841247E-324 & 1.79769313486232E308 & 14-15 cifras & 8 bytes\\
\hline
\end{tabular}
\end{center}

\subsection{Ejemplo}

El siguiente ejemplo muestra  el tamaño de los tipos de datos numéricos de Java. Note como se realiza una pequeña operación y el resultado como se ve afectado.

\begin{verbatim}
public class tipos {
    static public void main(String args[]) {
        byte a = 127;
        short b = 32767;
        int c =  2147483647;
        long d = 9223372036854775807l;
        float e = 3.402823E38f;
        double f = 1.7976931348623E308;
        
        System.out.println("byte   " + (byte)(a +1));
        System.out.println("short  " + (short)(b +1));
        System.out.println("int    " + (int)(c +1));
        System.out.println("long   " + (long)(d +1));

        System.out.println("float  " + (float)(e*1.1));
        System.out.println("double " + (double)(f*1.1));
        
    }
}
\end{verbatim}

Tenemos otros dos tipos básicos de variables, que no son para datos numéricos:

    char. Será una letra del alfabeto, o un dígito numérico, o un símbolo de puntuación. Ocupa 2 bytes. Sigue un estándar llamado Unicode (que a su vez engloba a otro estándar anterior llamado ASCII).
    boolean. se usa para evaluar condiciones, y puede tener el valor verdadero (true) o false (false). Ocupa 1 byte.
    
El siguiente ejemplo muestra como se declaran estos tipos de datos

\begin{verbatim}
public class otros_tipos {
    static public void main(String args[]) {
        char a = 'a';
        boolean b = true;
        
        System.out.println(a + " " + b);
        
    }
}
\end{verbatim}

Estos ocho tipos de datos son lo que se conoce como tipos de datos primitivos (porque forman parte del lenguaje estándar, y a partir de ellos podremos crear otros más complejos).

Nota para C y C++: estos tipos de datos son muy similares a los que se emplean en C y en C++, apenas con alguna pequeña diferencia, como es el hecho de que el tamaño de cada tipo de datos (y los valores que puede almacenar) son independientes en Java del sistema que empleemos, cosa que no ocurre en C y C++, lenguajes en los que un valor de 40.000 puede ser válido para un int en unos sistemas, pero desbordar el máximo valor permitido en otros. Otra diferencia es que en Java no existen enteros sin signo (unsigned). Y otra más es que el tipo boolean ya está incorporado al lenguaje, en vez de corresponder a un entero disinto de cero

\section{Variables y asignación}

La forma de declarar variables de estos tipos es la siguiente:

\begin{verbatim}
int numeroEntero;    // La variable numeroEntero será un número de tipo int
short distancia;     // La variable distancia guardará números short
long gastos;         // La variable gastos es de tipo long
byte edad;           // Un entero de valores pequeños
float porcentaje;    // Con decimales, unas 6 cifras de precisión
double numPrecision; // Con decimales y precisión de unas 14 cifras
\end{verbatim}

(es decir, primero se indica el tipo de datos que guardará la variable y después el nombre que queremos dar a la variable).

Se pueden declarar varias variables del mismo tipo a la vez:

\begin{verbatim}
int primerNumero, segundoNumero;    // Dos enteros
\end{verbatim}

Y también se puede dar un valor a las variables a la vez que se declaran:

\begin{verbatim}
int a = 5;            // a es un entero, e inicialmente vale 5
short b=-1, c, d=4;   // b vale -1, c vale 0, d vale 4
\end{verbatim}

Los nombres de variables pueden contener letras y números (y algún otro símbolo, como el de subrayado, pero no podrán contener otros muchos símbolos, como los de las distintas operaciones matemáticas posibles, ni podrán tener vocales acentuadas o eñes).

Vamos a aplicarlo con un ejemplo sencillo en Java que sume dos números:

\begin{verbatim}
    /* -------------------------------*
     *  Introducción a Java - Ejemplo *
     * -------------------------------*
     *  Fichero: suma.java            *
     *  (Suma dos números enteros)    *
     * -------------------------------*/
 

class Suma2 {

  public static void main( String args[] ) {

     int primerNumero = 56;    // Dos enteros con valores prefijados
     int segundoNumero = 23;

     System.out.println( La suma es: );  // Muestro un mensaje de aviso
     System.out.println( primerNumero+segundoNumero ); 

       // y el resultado de la operación
   }
}
\end{verbatim} 

El mismo código pero utilizando la representación como objetos

\begin{verbatim}
public class Sumados {
    int primernumero, segundonumero, suma;
    
    Sumados(int uno, int dos) {
        primernumero = uno;
        segundonumero = dos;
        suma = primernumero + segundonumero;
    }
    
    @Override
    public String toString(){
       return "La suma es " + suma;
    }
}
\end{verbatim}

Para ejecutar el código hacemos

\begin{verbatim}
 */
public class prueba {
    static public void main(String args[]) {

        Sumados s = new Sumados(1,2);
        System.out.println(s);
    }
}
\end{verbatim}

\section{Cadenas de caracteres}

En Java las cadenas se tratan de forma diferente a C/C++, donde las cadenas son matrices de caracteres en las que se indica el final de la cadena con un carácter de valor ‘\textbackslash{}0’.

En Java las cadenas son objetos de las clases predefinida String o StringBuffer, que están incluidas en el paquete java.lang.*.

Siempre que aparecen conjuntos de caracteres entre comillas dobles, el compilador de Java crea automáticamente un objeto String.

Si sólo existieran cadenas de sólo lectura (String), durante una serie de manipulaciones sobre un objeto String habría que crear un nuevo objeto para cada uno de los resultados intermedios.

El compilador es más eficiente y usa un objeto StringBuffer para construir cadenas a partir de las expresiones, creando el String final sólo cuando es necesario. Los objetos StringBuffer se pueden modificar, de forma que no son necesarios nuevos objetos para albergar los resultados intermedios.

Los caracteres de las cadenas tienen un índice que indica su posición. El primer carácter de una cadena tiene el índice 0, el segundo el 1, el tercero el 2 y así sucesivamente. Esto puede sonar familiar a los programadores de C/C++, pero resultar chocante para aquellos programadores que provengan de otros lenguajes.

Un ejemplo de uso de las cadenas de caracteres es:
\begin{verbatim}
public class Cadenas {
    static public void main(String args[]) {
        String a = "Hola Mundo";
        System.out.println(a);
    }
}
\end{verbatim}

\section{Expresiones}

Hay varias expresiones matemáticas que son frecuentes. Veremos cómo expresarlas en Java, y también veremos otras expresiones menos frecuentes.

Las que más encontramos normalmente son:

 
\subsection{Operadores Aritméticos}
	
Los operadores aritméticos más comunes son:

\begin{center}
\begin{tabular}{|c|c|}
\hline
Operador & Símbolo \\
\hline
Suma & + \\
Resta & - \\
Multiplicación &  *\\
División & /\\
\hline
\end{tabular}
\end{center}

Hemos visto un ejemplo de cómo calcular la suma de dos números; las otras operaciones se emplearían de forma similar.

\subsubsection{Ejemplo}

Dada la siguiente información, hacer un programa que permita calcular el área de un triángulo, de un cuadrado, y de un rectángulo, así como los volúmenes de un cilindro y de un cono.

El triángulo es un polígono formado por tres lados y tres ángulos. La suma de todos sus ángulos siempre es 180 grados. Para calcular el área se emplea la siguiente fórmula:
 

Área del triángulo = (base * altura) / 2

El cuadrado es un polígono de cuatro lados, con la particularidad de que todos ellos son iguales. Además sus cuatro ángulos son de 90 grados cada uno. El área de esta figura se calcula mediante la fórmula:
 
 
 Área del cuadrado = lado al cuadrado

El rectángulo es un polígono de cuatro lados, iguales dos a dos. Sus cuatro ángulos son de 90 grados cada uno. El área de esta figura se calcula mediante la fórmula:
 
Área del rectángulo = base * altura

El cilindro es el sólido engendrado por un rectángulo al girar en torno a uno de sus lados.
Para calcular su área lateral, su área total así como para ver su desarrollo pulsar sobre la figura anterior
Para calcular su volumen se emplea la siguiente fórmula:    

Volumen del cilindro = área de la base * altura

El cono es el sólido engendrado por un triángulo rectángulo al girar en torno a uno de sus catetos. Para calcular su área lateral, su área total así como para ver su desarrollo pulsar sobre la figura anterior
Para calcular su volumen se emplea la siguiente fórmula:  

Volumen del cono = (área de la base * altura) / 3

La implementación en Java es:

\begin{verbatim}
public class Areas_Volumenes {
    
  public static void main(String[] args)
  {
    // datos
 
    double base = 10, altura = 5, radio = 2;
 
    // areas
 
    double Atriangulo  = (base * altura) / 2.0;
    double Acuadrado   = base*base;
    double Arectangulo = base * altura;
 
    // volumenes
 
    double Abase       = 3.1416*radio*radio;
    double Vcilindro   = Abase * altura ;
    double Vcono       = Abase * altura / 3.0;
 
    System.out.println("Area de triangulo  = " + Atriangulo);
    System.out.println("Area de cuadrado   = " + Acuadrado);
    System.out.println("Area de rectangulo = " + Arectangulo);
 
    System.out.println("Volumen cilindro   = " + Vcilindro);
    System.out.println("Volumen cono       = " + Vcono);
 
  }
}
\end{verbatim}

El código del objeto cuadro puede ser escrito como

\begin{verbatim}
public class Cuadro {
    float base;
    
    Cuadro(float unabase){
        base = unabase;
    }
    
    float Area() {
        return base*base;
    }
    
    float Perimetro() {
        return 4.0f*base;
    }
    
    @Override
    public String toString(){
       return "El cuadro de base  " + base + " tiene un perimetro " + 
               Perimetro() + " y area = " + Area();
    }
}
\end{verbatim}

y para el triangulo como

\begin{verbatim}
public class Triangulo {
    float base, altura;
    
    Triangulo(float unaBase, float unaAltura) {
        base = unaBase;
        altura = unaAltura;
    }
    
    float Area() {
        return base*altura;
    }
    
    float Perimetro() {
        float lado;
        
        lado = (float)Math.atan(2.0f*altura/base);
        
        return (2.0f*lado + base);
    }
    
    @Override
    public String toString(){
       return "El triangulo de base  " + base + " y altura " + altura + " tiene un perimetro " + 
               Perimetro() + " y area = " + Area();
    }    
}
\end{verbatim}

El código para probar estas clase queda de la siguiente manera

\begin{verbatim}
public class prueba {
    static public void main(String args[]) {
        
        Cuadro a = new Cuadro(2.5f);
        System.out.println(a);
        
        Triangulo t = new Triangulo(2.0f, 2.5f);
        System.out.println(t);
    }
}
\end{verbatim}


\subsection{Otras operaciones matemáticas menos habituales}

En la subvención anterior describimos esas son las operaciones que todo el mundo conoce, aunque no haya manejado computadoras. Pero hay otras operaciones que son frecuentes en informática y no tanto para quien no ha manejado computadoras, pero que aun así deberíamos ver:

 
\begin{center}
\begin{tabular}{|c|c|}
\hline
Operación & Símbolo \\
\hline
Resto de la división & \% \\
Desplazamiento de bits a la derecha & $>>$\\
Desplazamiento de bits a la izquierda & $<<$ \\
Producto lógico (and) & \&\\
Suma lógica (or) & $|$\\
Suma exclusiva (xor) & $\hat{ }$ \\
Complemento & $\tilde{ }$ \\
\hline
\end{tabular}
\end{center}

El resto de la división también es una operación conocida. Por ejemplo, si dividimos 14 entre 3 obtenemos 4 como cociente y 2 como resto, de modo que el resultado de  $10 \% 3$  sería 2.

Las operaciones a nivel de bits deberían ser habituales para los estudiantes de informática, pero quizás no tanto para quien no haya trabajado con el sistema binario. No entraré por ahora en más detalles, salvo poner un par de ejemplos para quien necesite emplear estas operaciones: para desplazar los bits de a dos posiciones hacia la izquierda, usaríamos  $b << 2$; para invertir los bits de c (complemento) usaríamos tilde c;  para hacer una suma lógica de los bits de d y f sería  d $|$ f.
Incremento y asignaciones abreviadas.

\subsection{Operadores de Asignación}

Hay varias operaciones muy habituales , que tienen una sintaxis abreviada en Java. Por ejemplo, para sumar 2 a una variable a, la forma normal de conseguirlo sería:

a = a + 2;

pero existe una forma abreviada en Java:

a += 2;

Al igual que tenemos el operador += para aumentar el valor de una variable, tenemos -= para disminuirlo, /= para dividirla entre un cierto número, *= para multiplicarla por un número, y así sucesivamente.  Por ejemplo, para multiplicar por 10 el valor de la variable b haríamos

b *= 10;

También podemos aumentar o disminuir en una unidad el valor de una variable, empleando los operadores de incremento (++) y de decremento (--). Así, para sumar 1 al valor de a, podemos emplear cualquiera de estas tres formas:

a = a +1;
a += 1;
a++;

Los operadores de incremento y de decremento se pueden escribir antes o después de la variable. Así, es lo mismo escribir estas dos líneas:

a++;
++a;

Pero hay una diferencia si ese valor se asigna a otra variable al mismo tiempo que se incrementa/decrementa:

int c = 5;
int b = c++;

da como resultado c = 6 y b = 5 (se asigna el valor a b antes de incrementar c) mientras que

int c = 5;
int b = ++c;

da como resultado c = 6 y b = 6 (se asigna el valor a b después de incrementar c).  

\subsection{Operadores Relacionales}

También podremos comprobar si entre dos números (o entre dos variables) existe una cierta relación del tipo ¿es a mayor que b? o ¿tiene a el mismo valor que b?. Los operadores que utilizaremos para ello son:
	
\begin{center}
\begin{tabular}{|c|c|}
\hline
Operación & Símbolo\\
\hline
Mayor que & $>$ \\
Mayor o igual que & $>=$\\
Menor que & $<$ \\
Menor o igual que & $<=$ \\
Igual que & $==$ \\
Distinto de & $!=$\\
\hline
\end{tabular}
\end{center}

Así, por ejemplo, para ver si el valor de una variable b es distinto de 5, escribiríamos algo parecido (veremos la sintaxis correcta un poco más adelante) a

    SI  b != 5 ENTONCES ...

o para ver si la variable a vale 70, sería algo como (nuevamente, veremos la sintaxis correcta un poco más adelante)

    SI  a == 70 ENTONCES ...
 
Es muy importante recordar esta diferencia: para asignar un valor a una variable se emplea un único signo de igual, mientras que para comparar si una variable es igual a otra (o a un cierto valor) se emplean dos signos de igual.

\subsection{Operadores lógicos}

Podremos enlazar varias condiciones, para indicar qué hacer cuando se cumplan ambas, o sólo una de ellas, o cuando una no se cumpla. Los operadores que nos permitirán enlazar condiciones son:


\begin{center}
\begin{tabular}{|c|c|}
\hline
Operación & Símbolo\\
\hline
Y & \&\& \\
O & $||$\\
No & !\\
\hline
\end{tabular}
\end{center}

Por ejemplo, la forma de decir si a vale 3 y b es mayor que 5, o bien a vale 7 y b no es menor que 4 en una sintaxis parecida a la de Java (aunque todavía no es la correcta) sería:

\begin{verbatim}
    SI (a==3 && bb>5) || (a==7  && ! (b<4))
\end{verbatim}

\section{Conversión de datos}

En Java es posible transformar el tipo de una variable u objeto en otro diferente al original con el que fue declarado. Este proceso se denomina conversión, moldeado o tipado y es algo que debemos manejar con cuidado pues un mal uso de la conversión de tipos es frecuente que dé lugar a errores.

 Una forma de realizar conversiones consiste en colocar el tipo destino entre paréntesis, a la izquierda del valor que queremos convertir de la forma siguiente: Tipo VariableNueva = (NuevoTipo) VariableAntigua;

 Por ejemplo: 
 \begin{verbatim}
 int miNumero = (int) ObjetoInteger;      
 char c = (char)System.in.read();
\end{verbatim}
 
En el primer ejemplo, extraemos como tipo primitivo int el valor entero contenido en un campo del objeto Integer. En el segundo caso, la función read devuelve un valor int, que se convierte en un char debido a la conversión (char), y el valor resultante se almacena en la variable de tipo carácter c.
 
El tamaño de los tipos que queremos convertir es muy importante. No todos los tipos se convertirán de forma segura. Por ejemplo, al convertir un long en un int, el compilador corta los 32 bits superiores del long (de 64 bits), de forma que encajen en los 32 bits del int, con lo que si contienen información útil, ésta se perderá. Este tipo de conversiones que suponen pérdida de información se denominan “conversiones no seguras” y en general se tratan de evitar, aunque de forma controlada pueden usarse puntualmente.

De forma general trataremos de atenernos a la norma de que "en las conversiones debe evitarse la pérdida de información". En la siguiente tabla vemos conversiones que son seguras por no suponer pérdida de información.

\begin{center}
\begin{tabular}{|c|c|}
\hline
TIPO ORIGEN & TIPO DESTINO\\
\hline
byte & double, float, long, int, char, short\\
short & double, float, long, int\\
char & double, float, long, int\\
int & double, float, long\\
long & double, float\\
float & Double\\
\hline
\end{tabular}
\end{center}

No todos los tipos se pueden convertir de esta manera. Como alternativa, existen otras formas para realizar conversiones.


\subsection{Ejemplo}

Escribir un código en Java que permita redondear un número flotante a dos cifras significativas

\begin{verbatim}
public class redondea {
    static public void main(String args[]) {
        float pi = 3.1415926f;
        int pi_nvo = (int) (pi*100.0f + 0.5f);
        System.out.println(pi_nvo);
        pi = (float )pi_nvo/100.0f;
        System.out.println(pi);
    }
}\end{verbatim}

\section{Clases envoltorio o wrapper}

En ocasiones es muy conveniente poder tratar los datos primitivos (int, boolean, etc.) como objetos. Por ejemplo, los contenedores definidos por el API en el package java.util (Arrays dinámicos, listas enlazadas, colecciones, conjuntos, etc.) utilizan como unidad de almacenamiento la clase Object. Dado que Object es la raíz de toda la jerarquía de objetos en Java, estos contenedores pueden almacenar cualquier tipo de objetos. Pero los datos primitivos no son objetos, con lo que quedan en principio excluidos de estas posibilidades.

Para resolver esta situación el API de Java incorpora las clases envoltorio (wrapper class), que no son más que dotar a los datos primitivos con un envoltorio que permita tratarlos como objetos. Por ejemplo podríamos definir una clase envoltorio para los enteros, de forma bastante sencilla, con:

\begin{verbatim}
        public class Entero {
            private int valor;
            
            Entero(int valor) {
                this.valor = valor;
            } 

            int intValue() {
                return valor;
            }
        }
\end{verbatim}

La API de Java hace innecesario esta tarea al proporcionar un conjunto completo de clases envoltorio para todos los tipos primitivos. Adicionalmente a la funcionalidad básica que se muestra en el ejemplo las clases envoltorio proporcionan métodos de utilidad para la manipulación de datos primitivos (conversiones de / hacia datos primitivos, conversiones a String, etc.)

Las clases envoltorio existentes son:

    Byte para byte.
    Short para short.
    Integer para int.
    Long para long.
    Boolean para boolean
    Float para float.
    Double para double y
    Character para char.

Observe que las clases envoltorio tienen siempre la primera letra en mayúsculas.

Las clases envoltura se usan como cualquier otra:

\begin{verbatim}
        Integer i = new Integer(5);
        int x = i.intValue();
\end{verbatim}

Hay que tener en cuenta que las operaciones aritméticas habituales (suma, resta, multiplicación ...) están definidas solo para los datos primitivos por lo que las clases envoltura no sirven para este fin.

Las variables primitivas tienen mecanismos de reserva y liberación de memoria más eficaces y rápidos que los objetos por lo que deben usarse datos primitivos en lugar de sus correspondientes envolturas siempre que se pueda. 
