cursos online, formacion on-line, teleformación, Elearning, Cursos online de ofimática, diseño gráfico, web, gestión, idiomas, programacion - ADR Formación

2-Tipos y alcance de variables. Casting. Estructuras de programación. Clases envoltorio

Concepto de variable

Una variable es un contenedor de bits que representan a un valor. Se emplean para almacenar datos que pueden cambiar durante la ejecución de un programa. En función de los datos que almacenan se clasifican en: 

  • Variables primitivas: almacenan datos numéricos, valores lógicos o caracteres.
  • Variables referenciadas: asociadas a objetos o instancias de una clase. Por ejemplo, para almacenar cadenas de caracteres se empleará una variable referenciada asociada a la clase String, para almacenar información sobre la fecha actual, otra asociada a la clase Date, etc. Se estudiarán más adelante.

Además de estos dos tipos de variables se estudiarán los arrays de variables primitivas y de variables referenciadas. Un array, como se verá en el tema correspondiente, es una variable referenciada asociada a la clase Object (clase madre de todos los objetos Java).

Se va a profundizar un poco más en el concepto de variable: como se ha comentado anteriormente, no es nada más que un contenedor de bits que representan a un valor. Ocurre lo siguiente:

  • En el caso de variables primitivas, los bits representan un número entero que coincide con el valor de la variable, con lo que se va a trabajar a lo largo del programa. Por ejemplo, se tienen variables de tipo byte (utilizan 8 bits en memoria) que pueden almacenar números enteros comprendidos entre -128 y 127, de tipo int (utilizan 32 bits en memoria) para almacenar enteros entre, aproximadamente, -2150 millones y 2150 millones, de tipo float para números decimales, etc.

  • En el caso de variables referenciadas o asociadas a objetos, los bits representan un numerajo que permite acceder al valor de la variable, es decir, al objeto, pero no es el valor u objeto en sí.

Todos los nombres empleados para hacer referencia a variables deben cumplir lo siguiente:

  • Su primer carácter debe ser una letra, el símbolo del subrayado o el carácter dólar $.
  • No son válidos las palabras reservadas de Java.
  • No se admiten espacios en blanco.
  • Son case-sensitive (sensibles a mayúsculas).

Aparte de estas normas conviene que los nombres de las variables indiquen qué dato almacenan con el fin de facilitar la lectura del programa y, por otra parte, si un nombre tiene más de dos palabras la primera letra de la primera palabra irá en minúscula, la primera letra de la segunda palabra en mayúscula, ídem con la tercera y así sucesivamente.

Ejemplo:

int miVariableEntera=100;

Variables primitivas

Son variables que almacenan números enteros. Se pueden dividir en los siguientes tipos:

NOTA: el tipo de variable en que se almacena por defecto un numero entero es int. El valor por defecto asociado a cualquier variable entera no inicializada es 0.

 

Son variables que almacenan datos numéricos con decimales. Se pueden dividir en los siguientes tipos:

NOTA: el tipo de variable en que se almacena por defecto un numero decimal es double. El valor por defecto asociado a cualquier variable real no inicializada es 0.0.

 

Son variables que almacenan dos posibles valores: true o false. No se corresponden con ningún valor numérico.

Ejemplo:

boolean tienesCalor=true;

NOTA: el valor por defecto asociado a cualquier variable booleana no inicializada es false.

 

Son variables que almacenan caracteres individuales (letra, numero, signo ?, etc...). El carácter que se inicializa debe ir entre apóstrofes o comillas simples 'a'.

El código de caracteres empleado por Java es Unicode y recoge los caracteres de prácticamente todos los idiomas importantes del mundo (son unos 65.536). Los caracteres Unicode del alfabeto occidental corresponden a los primeros 256 enteros; es decir van desde [0, 255].

A cada carácter le corresponde unívocamente un número entero perteneciente al intervalo [0, 65536] o a [0, 255] si se trabaja sólo con el alfabeto occidental. Por ejemplo, la letra ñ es el entero 164. Más adelante se verá que el casting entre variables primitivas enteras y la variable char está permitido.

Ejemplo:

char miCaracter='n';

char miCaracter1=110;    (ídem antes, pero mediante el entero que le corresponde según Unicode)

char miCaracter2='\u006E'; (ídem antes, pero según notación Unicode. La notación Unicode, en general, es así: \uXXXX siendo X un dígito o cifra fundamental del sistema de numeración hexadecimal (0,1,2,...,9,A,B,...,F))

Asociado a este tipo de variable se tienen las secuencias de escape. Se emplean para representar caracteres especiales (por ejemplo, unas comillas dentro de una instrucción que exige una cadena entrecomillada) y caracteres no imprimibles como el tabulador, salto de línea, etc. Van precedidos de la contrabarra. Algunos de ellos se detallan en la tabla siguiente:

NOTA: el valor por defecto asociado a cualquier variable char no inicializada es '\u0000'

Ejemplo: todos los códigos de este tema se guardarán en c:\cursojava\tema2

Código fuente

Por consola:

Comienza programa

 

El valor de tengoCalor es true

El valor        de letra es n

El valor        de letra1 es n

El valor        de letra2 es n

Eso es

un mensaje

de tres lineas

Me llamo "Jesus"

Me llamo \Jesus\

Variables referenciadas

Asociadas a objetos o instancias de una clase. Se irán estudiando durante el curso.

Casting o transformaciones de tipo

El casting es un procedimiento para transformar una variable primitiva de un tipo a otro, o transformar un objeto de una clase a otra clase siempre y cuando haya una relación de herencia entre ambas (este último casting es el más importante y se verá más adelante).

Dentro del casting de variables primitivas se distinguen dos clases:

  • Implícito: no se necesita escribir código para que se lleve a cabo. Ocurre cuando se realiza una conversión ancha (widening casting), es decir, cuando se coloca un valor pequeño en un contenedor grande.

Ejemplo 1:

Ejemplo 2: similar al anterior.

En cambio,

  • Explícito: sí es necesario escribir código. Ocurre cuando se realiza una conversión estrecha (narrowing casting), es decir, cuando se coloca un valor grande en un contenedor pequeño. Son susceptibles de pérdida de datos.

Ejemplo 1:

NOTA: si se sustituyera la primera línea int num1=100 por int num1=1000000, el código compilaría bien, pero habría pérdida de datos, pues el 1000000 se sale del rango de short [-32768, 32767]. Al mostrar por consola el valor se obtendría un resultado incongruente.

Ejemplo 2:

Ejemplo 3: continuación del Ejemplo 2 del casting implícito

Para que la línea

compile debe hacerse un casting explícito a long

pero no

porque, en la línea anterior, 10000000000 es considerado int, mientras que en las de arriba, double.

Dicho esto, se va a analizar un ejemplo un tanto extraño.

Ejemplo extraño:

Dado que cualquier entero, por defecto, se almacena en un int (4 bytes), con la línea anterior se pretende colocar un valor grande (el int 10) en un contenedor pequeño (una primitiva de tipo byte con capacidad para 1 byte). Esto, según lo expuesto anteriormente, precisa de casting explícito.

Pero, resulta que no hace falta, ya que el compilador, cuando se trabaja con enteros, digamos que, provoca un "casting implícito contranatura" y transforma automáticamente a byte el int 10. Ocurriría lo mismo si se trabajara con short y char.

Lo que pasa (y esto es lo que resulta un tanto extraño) es que no ocurre lo anterior con los decimales: por eso, una línea como

provoca error de compilación. Recordar que cualquier decimal, por defecto, se almacena en un double (8 bytes) y que un tipo float tiene capacidad para 4 bytes. En los decimales, el compilador no fuerza el casting implícito contranatura. De ahí que sea necesario un casting explícito a float para evitar el fallo de compilación.

NOTA: quizá se evitarían estas situaciones, si el compilador no forzara el casting implícito contranatura a byte, short o char de un int y provocara error de compilación, del mismo modo que cuando se declara un float y no se castea explícitamente. Pero, de momento, esto es lo que hay.

Código de partida para explicar el casting entre variables primitivas que almacenan datos numéricos:

Las líneas 3 y 4 almacenan al número 10 mediante una variable primitiva de tipo byte vía "casting implícito contranatura", el 3000 mediante una de tipo short, también vía "casting implícito contranatura". Lo más intuitivo es definirlas mediante un casting explícito, pero tal y como están también se puede.

Supuestamente, la línea 5, almacena el 3000000000 mediante una variable de tipo long, vía casting implícito, pero es falso. Ocurre lo que se ha comentado en el Ejemplo 2 del casting implícito: 3000000000 no es considerado como long sino como int y 3000 millones no pertenece al rango asociado a int (aprox. [-2150 millones, 2150 millones]). Si se intenta compilar, se produciría error.

Supuestamente, la línea 6, almacena el 256.5 mediante una variable de tipo float (ocupa 4 bytes en memoria), vía "casting implícito contranatura", pero, como se ha comentado en el Ejemplo extraño, es falso, ya que en decimales nunca se produce. Debe castearse explícitamente a float.

El código correcto sería:

Código fuente

 

  • Una cuestión a tener en cuenta relacionada con el casting entre variables primitivas es la siguiente:

En Java se realizan automáticamente conversiones de una variable primitiva de un tipo a otra de otro de igual o mayor precisión.

La precisión depende del número de bytes ocupados en memoria y del rango de valores asociado: a mayor número de bytes ocupados, mayor precisión y mayor rango asociado. Así, pasar de byte a short, de short a int, de byte a int, . es automático; en definitiva: pasar de una variable primitiva de un tipo de la cadena de la siguiente línea a otra que se encuentre a su derecha es automático.

byte-->short-->int-->long-->float-->double

Así, por ejemplo, si un método necesita un long como argumento y se le pasa un entero perteneciente al rango de int, promociona automáticamente a long y no es necesario casting.

En cambio, si se le pasa un entero que se sale fuera del rango de int, es necesario realizar un casting para que la llamada al método no provoque error al compilar.

Un ejemplo de esto ocurre con el método estático de java.lang.Thread "void sleep(long retardo)" que introduce un retardo en la ejecución del código, coincidente con el entero, en milisegundos, que se le pasa al argumento. Este método se estudiará más adelante.

Por consola:

Hola

-- Después de tres segundos --

Adios

En cambio, si se sustituye

Thread.sleep(3000) por Thread.sleep(3000000000)

no compila ya que el entero que se le pasa no pertenece al rango de int y no puede promocionar a long automáticamente.

Para que compile es necesario hacer un casting explícito:

Thread.sleep(3000000000L)

 

  • Para finalizar con el casting entre primitivas, conviene tener en cuenta lo siguiente:
  • No es posible realizar casting entre una variable primitiva  booleana y cualquier otra variable primitiva.
  • Sí es posible realizar casting entre una variable primitiva char y una variable primitiva que almacene enteros.

Ejemplo:

Código fuente

Por consola:

ñ

ñ


Todos los derechos reservados © Copyright 2004 ADR Infor S.L.
Contacto: soporte@adrinfor.com