Programación en Java/Versión Para Imprimir

Esta es la versión para imprimir de Programación en Java.
  • Si imprimes esta página, o eliges la opción de Vista preliminar de impresión de tu navegador, verás que desaparecen este cuadro y los elementos de navegación de arriba y de la izquierda, pues no son útiles en una versión impresa.
  • Pulsando antes en Refrescar esta página te asegurarás de obtener los últimos cambios del libro antes de imprimirlo.
  • Para más información, puedes ver Wikilibros:Versión para imprimir.

Características del lenguaje

editar

Es un lenguaje sencillo de aprender. Su sintaxis es la de C++ “simplificada”. Los creadores de Java partieron de la sintaxis de C++ y trataron de eliminar de este todo lo que resultase complicado o fuente de errores en este lenguaje.

Java es un lenguaje orientado a objetos, aunque no de los denominados puros; en Java todos los tipos, a excepción de los tipos fundamentales de variables (int, char, long...) son clases. Sin embargo, en los lenguajes orientados a objetos puros incluso estos tipos fundamentales son clases, por ejemplo en Smalltalk.

El código generado por el compilador Java es independiente de la arquitectura: podría ejecutarse en un entorno UNIX, Mac o Windows. El motivo de esto es que el que realmente ejecuta el código generado por el compilador no es el procesador del ordenador directamente, sino que este se ejecuta mediante una máquina virtual. Esto permite que los Applets de una web pueda ejecutarlos cualquier máquina que se conecte a ella independientemente de qué sistema operativo emplee (siempre y cuando el ordenador en cuestión tenga instalada una máquina virtual de Java).

Conceptos clave
bytecodes
una especie de código máquina.
applets
programas embebidos en páginas Web.
Máquina Virtual
software que emula a un ordenador.


Características

editar
  • Lenguaje totalmente orientado a Objetos. Todos los conceptos en los que se apoya esta técnica, encapsulación, herencia, polimorfismo, etc., están presentes en Java.
  • Disponibilidad de un amplio conjunto de bibliotecas. Como ya se mencionó anteriormente, Java es algo más que un lenguaje. La programación de aplicaciones con Java se basa no solo en el empleo del juego de instrucciones que componen el lenguaje, sino, fundamentalmente, en la posibilidad de utilizar el amplísimo conjunto de clases que Sun pone a disposición del programador y con las cuales es posible realizar prácticamente cualquier tipo de aplicación.
  • Lenguaje simple. Java posee una curva de aprendizaje muy rápida. Resulta relativamente sencillo escribir applets interesantes desde el principio. Todos aquellos familiarizados con C++ encontrarán que Java es más sencillo, ya que se han eliminado ciertas características, como los punteros. Debido a su semejanza con C y C++, y dado que la mayoría de la gente los conoce aunque sea de forma elemental, resulta muy fácil aprender Java. Los programadores experimentados en C++ pueden migrar muy rápidamente a Java y ser productivos en poco tiempo.
  • Distribuido. Java proporciona una colección de clases para su uso en aplicaciones de red, que permiten abrir sockets y establecer y aceptar conexiones con servidores o clientes remotos, facilitando así la creación de aplicaciones distribuidas.
  • Interpretado y compilado a la vez. Java es compilado, en la medida en que su código fuente se transforma en una especie de código máquina, los bytecodes, semejantes a las instrucciones de ensamblador. Por otra parte, es interpretado, ya que los bytecodes se pueden ejecutar directamente sobre cualquier máquina a la cual se hayan portado el intérprete y el sistema de ejecución en tiempo real (run-time).
  • Robusto. Java fue diseñado para crear software altamente fiable. Para ello proporciona numerosas comprobaciones en compilación y en tiempo de ejecución. Sus características de memoria liberan a los programadores de una familia entera de errores (la aritmética de punteros), ya que se ha prescindido por completo de los punteros, y la recolección de basura elimina la necesidad de liberación explícita de memoria.
  • Seguro (?). Dada la naturaleza distribuida de Java, donde las applets se bajan desde cualquier punto de la Red, la seguridad se impuso como una necesidad de vital importancia. A nadie le gustaría ejecutar en su ordenador programas con acceso total a su sistema, procedentes de fuentes desconocidas. Así que se implementaron barreras de seguridad en el lenguaje y en el sistema de ejecución en tiempo real.
  • Indiferente a la arquitectura. Java está diseñado para soportar aplicaciones que serán ejecutadas en los más variados entornos de red, desde Unix a Windows Nt, pasando por Mac y estaciones de trabajo, sobre arquitecturas distintas y con sistemas operativos diversos. Para acomodar requisitos de ejecución tan diversos o variopintos, el compilador de Java genera bytecodes: un formato intermedio indiferente a la arquitectura diseñado para transportar el código eficientemente a múltiples plataformas hardware y software. El resto de problemas los soluciona el intérprete de Java.
  • Portable. La indiferencia a la arquitectura representa sólo una parte de su portabilidad. Además, Java especifica los tamaños de sus tipos de datos básicos y el comportamiento de sus operadores aritméticos, de manera que los programas son iguales en todas las plataformas. Estas dos últimas características se conocen como la Máquina Virtual Java (JVM).
  • Alto rendimiento.
  • Multihebra. Hoy en día ya se ven como terriblemente limitadas las aplicaciones que sólo pueden ejecutar una acción a la vez. Java soporta sincronización de múltiples hilos de ejecución (multithreading) a nivel de lenguaje, especialmente útiles en la creación de aplicaciones de red distribuidas. Así, mientras un hilo se encarga de la comunicación, otro puede interactuar con el usuario mientras otro presenta una animación en pantalla y otro realiza cálculos.
  • Dinámico. El lenguaje Java y su sistema de ejecución en tiempo real son dinámicos en la fase de enlazado. Las clases sólo se enlazan a medida que son necesitadas. Se pueden enlazar nuevos módulos de código bajo demanda, procedente de fuentes muy variadas, incluso desde la Red.
  • Produce applets. Java puede ser usado para crear dos tipos de programas: aplicaciones independientes y applets. Las aplicaciones independientes se comportan como cualquier otro programa escrito en cualquier lenguaje, como por ejemplo el navegador de Web HotJava, escrito íntegramente en Java. Por su parte, las applets son pequeños programas que aparecen embebidos en las páginas Web, como aparecen los gráficos o el texto, pero con la capacidad de ejecutar acciones muy complejas, como animar imágenes, establecer conexiones de red, presentar menús y cuadros de diálogo para luego emprender acciones, etc.


  • Lenguaje totalmente orientado a Objetos. Todos los conceptos en los que se apoya esta técnica, encapsulación, herencia, polimorfismo, etc., están presentes en Java.
  • Disponibilidad de un amplio conjunto de librerías. Como ya se mencionó anterirmente, Java es algo mas que un lenguaje. La programación de aplicaciones con Java se basa no solo en el empleo del juego de instrucciones que componen el lenguaje, sino, fundamentalmente, en la posibilidad de utilizar el amplísimo conjunto de clases que Sun pone a disposición del programador y con las cuales es posible realizar prácticamente cualquier tipo de aplicación.


  • Lenguaje simple. Java posee una curva de aprendizaje muy rápida. Resulta relativamente sencillo escribir applets interesantes desde el principio. Todos aquellos familiarizados con C++ encontrarán que Java es más sencillo, ya que se han eliminado ciertas características, como los punteros. Debido a su semejanza con C y C++, y dado que la mayoría de la gente los conoce aunque sea de forma elemental, resulta muy fácil aprender Java. Los programadores experimentados en C++ pueden migrar muy rápidamente a Java y ser productivos en poco tiempo.


  • Distribuido Java proporciona una colección de clases para su uso en aplicaciones de red, que permiten abrir sockets y establecer y aceptar conexiones con servidores o clientes remotos, facilitando así la creación de aplicaciones distribuidas.
  • Interpretado y compilado a la vez Java es compilado, en la medida en que su código fuente se transforma en una especie de código máquina, los bytecodes, semejantes a las instrucciones de ensamblador. Por otra parte, es interpretado, ya que los bytecodes se pueden ejecutar directamente sobre cualquier máquina a la cual se hayan portado el intérprete y el sistema de ejecución en tiempo real (run-time).
  • Robusto Java fue diseñado para crear software altamente fiable. Para ello proporciona numerosas comprobaciones en compilación y en tiempo de ejecución. Sus características de memoria liberan a los programadores de una familia entera de errores (la aritmética de punteros), ya que se ha prescindido por completo los punteros, y la recolección de basura elimina la necesidad de liberación explícita de memoria.
  • Seguro (?) Dada la naturaleza distribuida de Java, donde las applets se bajan desde cualquier punto de la Red, la seguridad se impuso como una necesidad de vital importancia. A nadie le gustaría ejecutar en su ordenador programas con acceso total a su sistema, procedentes de fuentes desconocidas. Así que se implementaron barreras de seguridad en el lenguaje y en el sistema de ejecución en tiempo real.
  • Indiferente a la arquitectura Java está diseñado para soportar aplicaciones que serán ejecutadas en los más variados entornos de red, desde Unix a Windows Nt, pasando por Mac y estaciones de trabajo, sobre arquitecturas distintas y con sistemas operativos diversos. Para acomodar requisitos de ejecución tan variopintos, el compilador de Java genera bytecodes: un formato intermedio indiferente a la arquitectura diseñado para transportar el código eficientemente a múltiples plataformas hardware y software. El resto de problemas los soluciona el intérprete de Java.
  • Portable La indiferencia a la arquitectura representa sólo una parte de su portabilidad. Además, Java especifica los tamaños de sus tipos de datos básicos y el comportamiento de sus operadores aritméticos, de manera que los programas son iguales en todas las plataformas. Estas dos últimas características se conocen como la Máquina Virtual Java (JVM).


Alto rendimiento


  • Multihebra Hoy en día ya se ven como terriblemente limitadas las aplicaciones que sólo pueden ejecutar una acción a la vez. Java soporta sincronización de múltiples hilos de ejecución (multithreading) a nivel de lenguaje, especialmente útiles en la creación de aplicaciones de red distribuidas. Así, mientras un hilo se encarga de la comunicación, otro puede interactuar con el usuario mientras otro presenta una animación en pantalla y otro realiza cálculos.
  • Dinámico El lenguaje Java y su sistema de ejecución en tiempo real son dinámicos en la fase de enlazado. Las clases sólo se enlazan a medida que son necesitadas. Se pueden enlazar nuevos módulos de código bajo demanda, procedente de fuentes muy variadas, incluso desde la Red.
  • Produce applets Java puede ser usado para crear dos tipos de programas: aplicaciones independientes y applets. Las aplicaciones independientes se comportan como cualquier otro programa escrito en cualquier lenguaje, como por ejemplo el navegador de Web HotJava, escrito íntegramente en Java. Por su parte, las applets son pequeños programas que aparecen embebidos en las páginas Web, como aparecen los gráficos o el texto, pero con la capacidad de ejecutar acciones muy complejas, como animar imágenes, establecer conexiones de red, presentar menús y cuadros de diálogo para luego emprender acciones, etc.

Primer programa

editar

Nuestro primer programa será sencillo y mostrará el saludo "Hola Mundo" en la pantalla. Para crear el programa necesitaremos realizar los siguientes pasos:

  1. Crear el código fuente. Un archivo de código fuente contiene texto escrito en el lenguaje de programación Java. Se puede utilizar un simple editor de texto para crear y editar el código.
  2. Compilar el código fuente. El compilador translada el código fuente en instrucciones que la máquina virtual de Java pueda entender. El compilador crea esas instrucciones en un archivo bytecode.
  3. Ejecutar el programa. El intérprete Java, instalado en el sistema operativo, implementa la máquina virtual de Java. Este intérprete transforma el bytecode en instrucciones que pueda entender el sistema operativo.


/*

  • Este programa escribe el texto "Hola Mundo" en la consola
  • utilizando el método System.out.println()
  • /

public class HolaMundo { public static void main (String[] args) { System.out.println("Hola Mundo");

Compilar el código

editar

Una vez guardado el código fuente, abrimos el MS-DOS o Command Prompt. Nos situamos en el directorio en donde se encuentra el archivo y luego ejecutamos la siguiente orden:

javac HolaMundo.java

Si todo sale bien, el compilador genera un archivo bytecode , HolaMundo.class en el mismo directorio en donde está el programa. De lo contrario muestra los errores que contiene el código.

Ejecutar el Código

editar

En el mismo directorio en donde estamos trabajando escribir la siguiente orden:

java HolaMundo


Esta vez escribimos el nombre del programa, pero sin la extensión. Si hemos realizado bien los pasos y tenemos instalado correctamente el JDK , tendremos en la pantalla el saludo:

Hola Mundo!

Para saber más

editar

Ejemplo de un clasico de la programación: en lenguaje Java:

public class HolaMundo {

	public static void main(String[] args) {
		System.out.println("Hola Mundo");
	}

}

Variables

editar

Las variables son una de las características fundamentales de los lenguajes de programación, permiten acceder a la memoria para almacenar y recuperar los datos con los que nuestros programas van a trabajar. Son por tanto el mecanismo que los lenguajes de programación ponen a nuestra disposición para acceder a la memoria.

Se trata de un mecanismo de lo más sencillo, sólo tenemos que dar un nombre a nuestras variables, a partir de ese momento el compilador traducirá de forma automática ese nombre en un acceso a memoria. Por ejemplo:

//Almacenamos un dato en memoria referenciado por el nombre edad 
edad = 5;
//Recuperamos el dato almacenado y lo modificamos
edad = edad + 1;

Java es un lenguaje tipado y nos obliga a declarar nuestras variables antes de poder hacer uso de ellas, con esta declaración le indicamos al compilador el espacio en memoria que debe de reservar para almacenar la información. Por ejemplo:

String cliente;

Aquí estamos reservando memoria para una variable de tipo String y la identificamos con el nombre “cliente”. De ahora en adelante si en el programa hablamos de cliente, estamos haciendo referencia a esa porción de memoria y al valor que contiene.

Podemos asignarle algún valor en el momento de declarar una variable. Por ejemplo:

 String cliente = "Isaac Newton";

Aquí reservamos memoria para una cadena de caracteres y le asignamos el valor "Isaac Newton". También podemos declararla y en otro lugar del programa fijarle un valor :

 String cliente; // declaración 
 ... // El programa sigue 
 cliente = "Isaac Newton"; // le damos un valor

La sentencia para declarar una variable se resume como:

Tipo_de_Dato Nombre_de_Variable [= Valor_inicial];

Definimos el tipo de dato, el nombre y opcionalmente su valor inicial.

Para ver como se utilizan las variables, podemos modificar el primer programa. Agregaremos una variable que contenga el texto que se mostrará en pantalla:

public class HolaMundo {
    public static void main(String[] args){
       String saludo = "¡Hola Mundo!";  
       System.out.println( saludo );
    }
}

Definimos una variable de tipo String con el nombre "saludo". En la declaración de la variable también la iniciamos con el valor "¡Hola mundo!". Luego llamamos al método que imprimirá el texto en la pantalla haciendo referencia a la variable. En el programa original, explícitamente introducíamos el texto que se mostraría, ahora solo escribimos el nombre de la variable. Cuando el intérprete se encuentre con el nombre de esta variable, tendrá que buscar el valor que almacene en la memoria para mostrarlo por pantalla.

Un variable puede cambiar su valor en el transcurso del programa (salvo que se preceda su definición con la palabra: final)

public class UsoVariables {
    public static void main(String args[]){
        String saludo;
        saludo = "Hola Mundo!";
        System.out.println(saludo);
        saludo = ("Estoy utilizando variables");
        System.out.println( saludo );
    }
}

Siempre debemos inicializar una variable. Al compilar el programa, el compilador de Java leerá el contenido de la variable y siempre verificará que tenga un valor. De lo contrario el programa no compilará y mostrará un error. Un ejemplo de este caso:

   int x;
   if (x > 0) { 
     saludo = "Hola Mundo!!!";
   }
   System.out.println( saludo );

En este caso el compilador mostrará un mensaje de error indicando que la variable x no se ha iniciado con ningún valor. Como se puede observar esta variable solo se inicia cuando se cumple una condición, sin embargo se indica que va a ser utilizada siempre. El compilador detecta este posible error. Un ejemplo de solución posible sería:

        int x = 1;

        if (x > 0) {
           saludo = "Hola Mundo!";
        }
        System.out.println( saludo );

Agregando estas líneas al final del código de la clase UsoVariables nos mostraría lo siguiente a la salida:

Hola Mundo!
Estoy utilizando variables
Hola Mundo!!!

Nombre de la variable

editar

El nombre debe ser único en el contexto del programa. Además debe seguir las siguientes reglas:

  • No puede ser una palabra reservada del lenguaje o un literal booleano (true o false)
  • Puede contener cualquier carácter Unicode, pero no puede comenzar con un número
  • No debe contener los símbolos que se utilicen como operadores ( + , - , ?, etc )


Por convención, los nombres de variables comienzan con una letra en minúscula. Si un nombre consiste en más de una palabra, se escribirá sin espacios entre ellas y cada palabra (salvo la primera) comenzará con una letra mayúscula (por ejemplo : estaBienEsteNombre )

Tipo de variable

editar

Cada variable debe tener un tipo de dato predefinido. Esto determina el rango de valores que puede almacenar y qué operaciones se pueden realizar así como el resultado que te dará. Por ejemplo, una variable de tipo entero puede almacenar números sin decimales y puede realizar operaciones aritméticas, pero no puede contener palabras.

Existen dos categorías de variables: las de tipo primitivo y las referenciadas. Una variable de tipo primitivo accede al valor asignado directamente. Las referenciadas acceden a través de un puntero, es decir, no almacenan un valor sino una dirección de memoria. Estas últimas son utilizadas por las matrices, las clases y las interfaces.


Tipos de datos primitivos
Tipo Tamaño y formato Rango
  enteros  
byte 8 bits - complemento a 2  
short 16 bits - complemento a 2  
int 32 bits - complemento a 2  
long 64 bits - complemento a 2  
  números reales  
float 32 bits - IEEE 754  
double 64 bits - IEEE 754  
  otros  
char 16 bits - caracteres UNICODE '\u0000' al '\uffff'
boolean 1 bit true o false

En otros lenguajes de programación, el formato o el tamaño de los tipos primitivos dependen del microprocesador o del sistema operativo en el que se están ejecutando. En cambio, Java pretende ser independiente de la plataforma y mantiene los formatos sin cambios. Para los caracteres alfanuméricos utiliza la codificación UNICODE de 16 bits, para permitir la inclusión de varios alfabetos.

Para saber más

editar

Literales

editar

Pueden existir varias formas de representar un valor. Por ejemplo al tener el número 100, significa exactamente 100 en una base decimal, pero hablamos de 4 en una base binaria o 256 en hexadecimal. Para evitar ambigüedades, en Java se establecieron algunas normas.

Literales enteros

editar

Existen 3 maneras de representar el valor de un número entero. Si se escribe el número solamente, éste representa un número en base decimal. Si tiene un cero delante estamos escribiendo octales y si tiene el prefijo "0x" el valor está representado en base hexadecimal. Por ejemplo:

Base de numeración valor valor decimal
Decimal 100 100
Octal 0100 64
Hexadecimal 0x100 256

Para indicarle al compilador que un valor dado es de tipo long debemos incluir el sufijo L:

long largo= 800L;

Literales de números reales

editar

Al tratar con números reales introducimos el punto decimal o utilizamos la notación científica. Por ejemplo:

double v = 300000.0;  // notación normal
double v = 3.0e+5;     // notación -científica

En el ejemplo el valor 3.0e+5 significa  . La letra e denota la mantisa, y da igual si la escribimos en mayúscula o minúscula.

Para determinar si estamos hablando de float o double, al número se le agrega un sufijo: F o f para float y D o d para double. Si no colocamos un sufijo el compilador lo toma como double.

Literales char

editar

Una variable de tipo char almacena un carácter Unicode. Este sistema de codificación amplía la escasez de opciones que tiene la codificación ASCII para incluir otros alfabetos. Podemos escribir en griego, hebreo o en vietnamita sin que el compilador proteste. Un literal de tipo char se expresa encerrando el carácter entre comillas simples:

char caracter = 'z';

Otra forma de representar un carácter es indicando el código Unicode en hexadecimal, anteponiendo los símbolos \u, todo entre comillas simples. De esta manera el símbolo arroba ( @ ) se escribe:

char arroba = '\u0040';

El primer byte de la codificación Unicode es la misma que el viejo y querido ASCII

Literales boolean

editar

Sencillamente true o false (verdadero o falso) sin comillas y en minúscula. No tienen correlación con ningún número como ocurre en el lenguaje C que teníamos al 0 como false y al 1 como true.

Literales String

editar

El tipo String no es un tipo de dato primitivo. Pero se comporta como si lo fuera. Para indicar una cadena de caracteres se encierran entre comillas dobles.

String cadena = "Time is money";

Ejemplos de valores literales

editar
Literal Tipo de dato
"Gato" String
"G" String
'G' char
123 int
8000L long
3.14 double
3.14D double
3.14f float
26.45e-45 double
'\u00ff' char
'c' char
"true" String
true boolean

En los sufijos que tenemos para identificar el tipo de dato no importa si son en minúscula o mayúscula. Pero por convención se utilizan en mayúscula, pues se puede confundir al leer el código una ele minúscula ( l ) con un uno ( 1 ). Hay que tener cuidado de no olvidarnos los sufijos cuando sean necesarios. El siguiente código da un error en tiempo de compilación:

float f = 3.14;

El compilador nos dará el error de "possible loss of precision" (posible pérdida de precisión). Esto se debe a que sin la F atrás, estamos indicando un valor de tipo double. El compilador se niega a comprimir un double de 64 bits en un float de tan solo 32 bits. Lo solucionamos de esta manera:

float f = 3.14f;

Y le alegramos la vida a un compilador gruñón.

La palabra reservada final

editar

En una aplicación posiblemente nos encontremos con algún valor que permanece constante durante la ejecución. Podemos definirla como una variable común pero perderíamos el control. Por allí, en algún descuido, se cambiaría de valor pero no nos enteraríamos. Podemos agregar a la definición de la variable el modificador final, que indica que a esa variable solo se le puede asignar un valor u objeto una única vez. La sintaxis es la siguiente:

final tipo_variable nombre_de_variable = valor;  

Por ejemplo :

final int unaConstante = 10;

Si tratamos de modificar el valor de una variable con el modificador final, el compilador indicará un error. Una vez definido el valor no se puede modificar.

Realmente, lo que permanece constante es la asignación de un objeto a esa variable, no los atributos internos que pueda tener ese objeto. Por ejemplo, en el siguiente caso:

final Ciudadano juan = new Ciudadano();

habríamos creado al ciudadano 'juan' y ya nunca más se le podrá asignar a 'juan' otra instancia de Ciudadano. Sin embargo, es posible cambiar los datos internos de ese ciudadano:

juan.setApellido("Pérez");

el objeto 'juan' ha cambiado internamente.

Con el modificador final evitaremos lo siguiente:

Ciudadano pepe = new Ciudadano();
juan = pepe;

La última línea no compilaría pues 'juan' fue declarado con final, así que no se le puede asignar nada nuevo.


Secuencias de Escape

editar

Las secuencias de escape son pequeñas constantes que nos brindan una gran utilidad; para comprenderlo mejor este ejemplo (en consola):

 public class SecEsc01 {
     public static void main(String args[]) {
         System.out.println("Este es un ejemplo de Secuencias de Escape");
     }
 }

Este ejemplo presenta una linea de texto, pero, ¿qué pasa si queremos este texto en tres lineas?, tendríamos que escribir :

 public class SecEsc02 {
     public static void main(String args[]) {
         System.out.println("Este es un ejemplo");
         System.out.println("de");
         System.out.println("Secuencias de Escape");
     }
 }

Es algo más tedioso, menos mal que existen las secuencias de escape en Java, las cuales nos ahorrarán el trabajo de la siguiente manera:

 public class SecEsc03 {
     public static void main(String args[]) {
         System.out.println("Este es un ejemplo\nde \nSecuencias de Escape");
     }
 }

Pero este es solo un ejemplo. ¿Qué pasa si queremos una pequeña tabulacion? Tendríamos que teclear la barra espaciadora hasta la medida del espacio que queremos, java también soluciona esto de la siguiente manera:

 public class SecEsc04 {
     public static void main(String args[]) {
         System.out.println("\tTexto tabulado");
     }
 }

A continuación hay una lista de secuencias de escape:

  • \n -----> Nueva línea.
  • \t -----> Tabulador.
  • \r -----> Retorno de carro.
  • \f -----> Comienzo de página.
  • \b -----> Borrado a la izquierda.
  • \\ -----> El carácter barra inversa ( \ ).
  • \' -----> El carácter comilla simple ( ' ).
  • \" -----> El carácter comillas dobles ( " ).

Arrays

editar
Arrays


En Java, un Array o (en español arreglo) es un grupo de variables llamadas elementos o componentes que contienen variables las cuales son de un mismo tipo. En java, a diferencia del lenguaje C, existe un tipo de variable “especial”, el Array o matriz. Este tipo de variables no es más que un conjunto secuencial de memoria a las que se accede a través de un índice de posición.

Las matrices en Java son objetos, por lo que cuentan con propiedades y métodos para manipularlos. Se pueden declarar matrices de tipos de datos primitivos y de objetos.

Para hacer referencia a un elemento en especial en un arreglo, se debe especificar el nombre que llevará la referencia al arreglo y el número de la posición del elemento en el arreglo. El número de la posición del elemen- to se conoce como el índice o subíndice del elemento.

Existen varias maneras de declarar un array, por ejemplo:

Sintaxis:


  • tipodedato nombre [] = new tipodedato[tamaño]
  • int c[] = new int[ 12 ];
    


  • tipodedato[] nombre = new tipodedato[tamaño]
  • int[] c = new int[ 12 ];
    


  • tipodedato nombre [] nombre = new tipodedato[tamaño]
  • int c[ ];
    c = new int[ 12 ];
    


    Como puedes observar puedes inicializar un array al momento de declararlo o postergar esta operación para cuando sea necesario.

    Para inicializar un array existen 2 maneras:

    • int[] matriz=new int[4] o
    • int[] matriz={100,200,302,400}


    Como podrás concluir, en la primera declaras el array nada más, diciéndole la cantidad de memoria secuencial que se debe reservar, en el segundo ejemplo se inicializa el array dándole los valores que va a contener (obviamente la cantidad de memoria secuencial reservada será igual a la cantidad de elementos insertados).

    Al momento de inicializar una matriz de la manera :

    • int[] matriz=new int[4]

    cada posición de la matriz sera inicializada con el valor predeterminado del tipo de variable. Por ejemplo si la matriz es de tipo boolean, todas las posiciones de la matriz serán inicializadas con el valor false (ya que este es valor predeterminado de este tipo de dato), por el contrario si la matriz fuese de un tipo no primitivo, el valor que contendrá cada casilla sera null.

    A continuación tienes una lista de los valores predeterminados de cada tipo de dato:

    Tipo de Dato-->Valor
    byte-->0
    short-->0
    int-->0
    long-->0
    float-->0.0
    double-->0.0
    char-->/u0000
    boolean-->false
    Object (Cualquier tipo de Objeto)-->null

    Para obtener el tamaño de un array de manera dinámica se utiliza la propiedad .length. Esta propiedad es común para todos los arrays. También es importante saber que las matrices se empiezan a enumerar desde el número cero (0), por tanto para acceder al valor almacenado en la última posición deberás colocar el tamaño de la matriz menos 1 unidad.

    Al momento de tratar de acceder a una posición fuera del rango de la matriz se lanzará un excepción de tipo java.lang.ArrayIndexOutOfBoundsException (esta excepción es una excepción no chequeada, por lo que no es necesario colocar un bloque try/catch en el código)

    Pasaremos con un ejemplo:

     public class Arrays01 {
         public static void main(String args[]) {
             int ita_nro[] = new int[4];
             for (int it_cont = 0; it_cont < 4; it_cont++){
                 ita_nro[it_cont] = it_cont * 2;
                 System.out.println(ita_nro[it_cont]);
             }
         }
     }
    

    Programación en Java/arrays secuencias finales/inluye un programa como ejemplo

    Operadores

    editar
    ← Secuencias de Escape Operadores Operadores aritméticos →


    Un operador realiza una función, toma uno o más argumentos y devuelve un resultado. Cuando vimos las variables, definimos un tipo de dato con un conjunto de operaciones asociadas. Es de esperar que podamos realizar operaciones aritméticas con números y lógicas con los booleanos. Estas operaciones se representan mediante operadores.

    Los operadores, al igual que los métodos, se pueden sobrecargar, es decir se puede redefinir su funcionalidad dependiendo de los tipos de datos de los operandos que reciba. Así, podemos indicar que el operador (+) realice una suma aritmética si los operandos que recibe son dos enteros y una concatenación si recibe una cadena y otro objeto.

    Operadores aritméticos

    editar
    ← Operadores Operadores aritméticos Operadores relacionales →


    Realizan las operaciones aritméticas básicas: suma (+), resta (-), multiplicación (*) ,división (/) y módulo (%) para datos de tipo numérico, tanto enteros como reales. Estas son operaciones binarias porque admiten dos operandos.

    Ejemplo de utilización de estos operadores:


    public class Aritmetica{
    	public static void main(String[] args){
    		int i      = 12;
    		int j      = 10;
    		int suma   = i + j;
    		int resta  = i - j;
    		int mult   = i * j;
    		int div    = i / j;
    		int modulo = i % j;
    		
    		System.out.print("Suma :");
    		System.out.println(suma );
    		System.out.print("Resta :");
    		System.out.println(resta);
    		System.out.print("Multiplicacion :");
    		System.out.println(mult);
    		System.out.print("Division :");
    		System.out.println(div);
    		System.out.print("Modulo :");
    		System.out.println(modulo);	
    	
    	}
    		
    }
    


    El resultado de estas operaciones no puede quedar almacenado en una variable de tipo short o byte, por más pequeño que sea. Si tramos de compilar esto:

    short i = 1;
    short j = 1;
    short x = i + j;
    

    Tendremos un "possible lost of precision" como respuesta, por más que el pequeñito 2 entre holgadamente en una variable short. El compilador evita que al utilizar estos tipos de datos no nos pasemos de largo. Pero de todas formas me voy a vengar. Analicemos el siguiente código:

    public class IntGrande{
    	public static void main(String[] args){
    		int j = 2147483647;
    		int i = j + 1;
    		System.out.println("El valor obtenido es " + i);
    		
    	}
    		
    }
    

    El valor 2147483647 (es decir 2^31 - 1 ) es el más grande que puede tolerar un int. Pero veamos que pasa al sumarle uno más. El compilador se queda mudo y cae en nuestra trampa. Ejecutamos el programa y obtenemos:

    El valor obtenido es -2147483648 
    

    Desastroso, ¿Verdad? Veamos lo que pasó: Teníamos el valor máximo para los int:

    01111111111111111111111111111111 : 2147483647 en números binarios.
    00000000000000000000000000000001 : le sumamos 1
    10000000000000000000000000000000 : Resultado: -2147483648 complemento a 2
    

    Esta anomalía se la conoce como “overflow” (desbordamiento). El procesador puede identificar un resultado con este problema comparando los signos. Es de esperar que si sumamos dos números positivos, no nos dé como resultado un número negativo. Pero el intérprete de Java no nos avisa, por lo tanto tenemos que cuidarnos al trabajar cerca de los extremos.

    Sigamos metiéndonos en embrollos. Veamos ahora que ocurre si tratamos de dividir cualquier número por cero. Para la verificación escribimos este programa:

    public class DivCero{
    	public static void main(String[] args){
    		int x = 5;
    		int y = 0;
    		int z = x/y;
    		System.out.println(z);
    	}
    		
    }
    

    No tenemos noticias al compilar. Pero al ejecutar el programa, el intérprete nos manda a pasear con la siguiente nota:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
    

    Veremos mas adelante cómo controlar el ánimo del interprete cuando ocurren estos errores, aquí conocidos como excepciones. La moraleja es que no se puede dividir un entero por cero.

    Sigamos dando pelea, no nos dejemos intimidar. Probemos que ocurre con los números reales:

    public class DivCeroFloat{
    	public static void main(String[] args){
    		float x = 5.0f;
    		float y = 0.0f;
    		float z = x/y;
    		System.out.println(z);
    	}
    		
    }
    

    Compilamos y no escuchamos nada. Ejecutamos el programa...

    Infinity 
    

    Ni error ni cosas raras, el float se aguantó los malos tratos. Esto ocurre porque los números reales en su representación binaria soportan el valor infinito.

    Operadores aritméticos unarios

    editar

    Dentro de los operadores aritméticos tenemos los unarios + y – que simplemente operan con el signo de un valor dado. Por ejemplo:

    int h = -1;
    int m = +h; // es equivalente a m = h * (+1)
    int n = -h; // es equivalente a n = h * (-1)
    

    El operador – se encarga de cambiar el signo, y el + sencillamente deja el signo como está. Nuevamente no podemos almacenar el resultado en enteros cortos, los tipos byte y short los transforma en int. Dentro del catálogo de operadores tenemos algunos unarios más. Se trata del auto incremental ++ y del auto decremental --. Respectivamente, suma y resta una unidad al valor. Ambos operadores pueden ser sufijos, es decir se coloca antes del operando o posfijo que se sitúa detrás. Veamos algunos ejemplos:

    int i = 1; 
    i++; 
    ++i; 
    i--;
    --i;
    

    En este ejemplo estamos incrementado y decrementando el valor de i. A priori parece que los operadores funcionan igual, tanto como posfijo como sufijo, pero su comportamiento es diferente. Observemos lo que ocurre en este ejemplo:

    public class Diferentes{
    	public static void main(String[] args){
    		int i = 2;
    		int j = 2;
    		System.out.println(i++);
    		System.out.println(++j);
    		System.out.print("Estado Final (i) :");
    		System.out.println(i);
    		System.out.print("Estado Final (j) :");
    		System.out.println(j);
    	}
    }
    

    todo es practico. Partiendo del mismo valor, vemos que j se incrementó, mientras que la variable i se mostró sin cambios. Si colocamos el operador como sufijo, primero se evalúa la variable y luego se realiza la operación. En el caso de la variable i, antes de incrementar su valor se mostró por pantalla. Para la variable j el procedimiento fue inverso. Antes de mostrar su valor se incrementó.

    Operadores relacionales

    editar
    ← Operadores aritméticos Operadores relacionales Operadores booleanos →


    Revisando algunas definiciones matemáticas, nos enteramos que los números conforman un conjunto ordenado. Cada uno tiene una posición relativa. Sabemos que el 2 "es menor que" el 4 y que el 6 "es más grande que" el 1. Al comparar dos números, realizamos una función de relación.

    En java disponemos de los operadores relacionales para verificar si se cumple una relación. Por ejemplo el operador de equivalencia ( == ) nos devuelve un valor de verdadero si los operandos son iguales. Estas operaciones comparan dos valores numéricos y devuelven un valor booleano.

    Operadores relacionales
    Operador Utilización Resultado
    > A > B verdadero si A es mayor que B
    >= A >= B verdadero si A es mayor o igual que B
    < A < B verdadero si A es menor que B
    <= A <= B verdadero si A es menor o igual que B
    == A == B verdadero si A es igual a B
    != A != B verdadero si A es distinto de B


    Aquí tenemos un programa para ver el funcionamiento de estos operadores :

    public class relaciones {
       public static void main(String args[]){
           int    i = -3;
           byte   b = 5;
           float  f = 1e-10f;
           double d = 3.14;
           boolean b1 = i > i;
           boolean b2 = i < b;
           boolean b3 = b <= f;
           boolean b4 = f >= d;
           boolean b5 = d != 0;
           boolean b6 = 1 == f;
    
           System.out.println("b1: " + i + " > " + i + " = " + b1);
           System.out.println("b2: " + i + " < " + b + " = " + b2);
           System.out.println("b3: " + b + " <= " + f + " = " + b3);
           System.out.println("b4: " + f + " >= " + d + " = " + b4);
           System.out.println("b5: " + d + " != " + 0 + " = " + b5);
           System.out.println("b6: " + 1 + " == " + f + " = " + b6);
       }
    
    }
    

    No nos olvidemos de los char, que también participan. Podemos comparar caracteres, pues internamente están almacenados como números.

    char a = 'A';
    char b = 'B';
    boolean x = a > b;
    

    Entre los booleanos solo se permiten los operadores de equivalencia, es igual (==) o es distinto (!= )

    boolean x = true;
    boolean y = x == x;
    boolean z = x != y;
    

    Operadores booleanos

    editar
    ← Operadores relacionales Operadores booleanos Operadores de bits →


    Como deben suponer, trabajan con operandos booleanos. Realizan las operaciones lógicas de conjunción (AND), disyunción (OR), negación (NOT) y la disyunción exclusiva (XOR).

    Operadores booleanos
    Nombre Operador Utilización Resultado
    AND && A && B verdadero cuando A y B son verdaderos. Evaluación condicional.
    OR || A || B verdadero cuando A o B son verdaderos. Evaluación condicional.
    NOT ! !A verdadero si A es falso.
    AND & A & B verdadero cuando A y B son verdaderos. Siempre evalúa ambos operandos.
    OR | A | B verdadero cuando A o B son verdaderos. Siempre evalúa ambos operandos.
    XOR ^ A ^ B verdadero cuando A y B son diferentes

    Cada una de estas operaciones tiene asociada una tabla de verdad. Esto nos permite ver el resultado de un operador aplicado a las distintas combinaciones de valores que pueden tener los operandos. A continuación mostraremos como se comporta el operador AND mediante su tabla de verdad.

    public class TablaAnd {
       public static void main(String args[]){
              boolean x = true;
              boolean y = false;
              boolean a1 = x && x;
              boolean a2 = x && y;
              boolean a3 = y && x;
              boolean a4 = y && y;
    
              System.out.println("Tabla de verdad de la conjunción");
              System.out.println( x + " AND " + x + " = " + a1 );
              System.out.println( x + " AND " + y + " = " + a2 );
              System.out.println( y + " AND " + x + " = " + a3 );
              System.out.println( y + " AND " + y + " = " + a4 );
       }
    
    }
    

    Si probamos a quitar un ampersand ( & ) del operador, vemos que obtenemos los mismos resultados. Existen dos operadores AND, uno con dos símbolos & y el otro con uno solo. También tenemos dos operadores OR.

    boolean x1 = operando1 && operando2; 
    boolean x2 = operando1 & operando2;
    
    boolean y1 = operando1 || operando2;
    boolean y2 = operando1 |  operando2;
    

    Parece extraño, sobre todo porque tienen la misma tabla de verdad. Pero internamente tienen un comportamiento diferente.

    Cuando estamos en presencia de un operador con un solo símbolo, siempre se evalúan ambos operandos. En cambio para el operador con el símbolo repetido, su evaluación cambia según el valor del primer operando. Por ejemplo tenemos la siguiente operación.

    boolean x = true && false;
    

    El resultado es falso, pero el intérprete tiene que mirar el segundo operando para saberlo.

    boolean x = false && true
    

    Aquí ni se molesta en mirar el último operando, porque la operación AND es verdadera solamente cuando ambos operandos son verdaderos.

    En el caso del operador OR, se evalúa el segundo operador si el primero es falso. Cuando es verdadero, no tiene en cuenta el otro operando. El resultado es verdadero sin importar el valor del segundo.

    Veamos un caso extremo para mostrar como funciona la evaluación condicional. Tenemos el siguiente programa en donde pretendemos hacer saltar al intérprete con un error.

    public class Condicional {
       public static void main(String args[]){
              int x = 0;
              int y = 2;
              boolean b = ( x != 0 ) && ( ( y / x ) != 0 );
              System.out.println(b);
       }
    }
    

    Sin ningún tipo de emoción, aburridamente el intérprete nos avisa que el resultado es "false". Ahora verá. Quitemos un símbolo & y quedémonos con uno solo. El resultado es otro :

    java.lang.ArithmeticException: / by zero
    

    La primera vez verificó que x!=0 era falso, entonces dio por terminada la operación con el resultado falso. Cuando cambiamos de operador, evaluó los dos operandos y cayó en nuestra trampa. Tuvo que calcular cuanto es y / x dando luego un error de división por cero.

    Los operadores booleanos son muy amigos de los relacionales. Se llevan bien porque los últimos dan resultados booleanos. Entre ambos tipos de operadores se pueden construir instrucciones mas complejas.

    Por ejemplo, queremos saber si un número está dentro de un rango. Solo tenemos que compararlo con los extremos:

    int     y = 4;
    boolean x = ( y > 3 ) && ( y < 6 );
    

    Ahora deseamos saber si una variable tiene el valor "a" no importando si es mayúscula o minúscula.

    char c = 'b';
    boolean x = ( c == 'a' ) || ( c == 'A' );
    

    No olviden que el operador de equivalencia (==) tiene dos símbolos igual (=), si colocan uno solo les dará un error de asignación.

    Operadores de bits

    editar
    ← Operadores booleanos Operadores de bits Operadores de asignación →


    Como sabrán, los datos en una computadora internamente se representan en código binario. El microprocesador solo entiende de ceros y unos. Luego, mediante una serie de procesos, nosotros vemos a este código ya transformado en números, caracteres, imágenes y sonido. Pero en realidad en la trastienda todo sigue siendo binario.

    Los Bits

    editar

    El método más sencillo de representación son los números naturales. Por ejemplo, si tengo el número 85 en decimal, solo tengo que llevarlo a binario y obtengo una serie de unos y ceros:

    1010101 = 85 en binario 
    


    Cada dígito (un cero o un uno) de este número se llama bit. Java tiene una serie de operadores capaces de manipular estos dígitos, son los operadores de bits.

    Operadores de bits
    Operador Utilización Resultado
    << A << B Desplazamiento de A a la izquierda en B posiciones
    >> A >> B Desplazamiento de A a la derecha en B posiciones, tiene en cuenta el signo.
    >>> A >>> B Desplazamiento de A a la derecha en B posiciones, no tiene en cuenta el signo.
    & A & B Operación AND a nivel de bits
    | A | B Operación OR a nivel de bits
    ^ A ^ B Operación XOR a nivel de bits
    ~ ~A Complemento de A a nivel de bits


    Para operar a nivel de bit es necesario tomar toda la longitud predefinida para el tipo de dato. Estamos acostumbrados a desechar los ceros a la izquierda en nuestra representación de números. Pero aquí es importante. Si trabajamos una variable de tipo short con un valor de 3, está representada de la siguiente manera :

    0000000000000011
    

    Aquí los 16 bits de un short se tienen en cuenta.

    Desplazamientos

    editar

    Los operadores de desplazamiento, mueven los bits a la izquierda o a la derecha. El primer operando será la victima a sacudir. El segundo indicará cuantas posiciones.

    Desplazamiento a la izquierda

    editar

    Deseamos correr el número 33 dos posiciones a la izquierda. Entonces realizamos :

    int j = 33;
    int k = j << 2;
    

    Este es el resultado:

    00000000000000000000000000100001 : j = 33
    00000000000000000000000010000100 : k = 33 << 2 ; k = 132                                                           
    

    Cada "hueco" que queda a la derecha tras correr este número se rellena con ceros. Los bits a la izquierda se pierden, no es una operación de rotación. Si prestamos atención, observaremos que esta operación multiplicó a j por 2 tantas veces como posiciones se ha desplazado. En este caso se multiplicó por 4 ( 2 x 2 ). Hay que notar que el signo del número puede cambiar tras la operación (por ejemplo 1 << 31 = -2147483648).

    Desplazamiento a la derecha con signo

    editar

    Volvamos a colocar como estaban los bits del caso anterior. Queremos obtener nuevamente el número 33. Para esto desplazamos el número 132 dos posiciones a la derecha.

    int k = 132;
    int m = k >> 2;
    

    Como resultado obtenemos el número original.

    00000000000000000000000010000100 : k = 132    
    00000000000000000000000000100001 : m = 132 >> 2 ; m = 33
    

    Podemos ver que el corrimiento a la derecha realiza una división de enteros. Divide por 2, tantas veces como posiciones desplazadas.

    Veamos que ocurre si pretendemos realizar un desplazamiento a la derecha con un número negativo. Tengan en cuenta que la representación de números es de complemento a 2. Si tengo una variable de tipo int con el valor –1 , internamente está almacenada de la siguiente forma :

    11111111111111111111111111111111 : -1 complemento a 2 
    

    Ahora realicemos un programa para ver que ocurre con el desplazamiento.

    public class CorreNeg {
       public static void main(String args[]){
              int x = -1;
              int y = x >> 2;
              System.out.println("El resultado es: " + String.valueOf(y));
       }
    }
    

    La salida del programa nos indica que:

    El resultado es: -1
    

    Quedó exactamente igual. Prueben de correr el número tantas posiciones como tengan ganas y obtendrán el mismo resultado. Esto ocurre porque en el desplazamiento, los "huecos" que quedan a la izquierda se rellenan con el bit uno (1), quedando inalterable.

    Este operador desplaza el conjunto de bit a la derecha y agrega a la izquierda los bits que faltan según el bit de signo, o sea el más significativo. Si se encuentra con un número positivo, el bit de signo vale 0, entonces agrega ceros, en cambio si son negativos el bit de signo vale 1, entonces agrega unos. Este proceso, denominado extensión de signo mantiene el signo del número como si se tratara de una división. Por esto se lo conoce como desplazamiento con signo.

    Desplazamiento a la derecha sin signo

    editar

    Modifiquemos ligeramente el programa anterior agregándole al operador un símbolo >. Nos queda de esta manera :

    int x = -1;
    int y = x >>> 2;
    

    Si ejecutamos el programa nos dice lo siguiente :

    El resultado es: 1073741823
    

    Veamos de donde salió este número raro. Si lo llevamos a binario tenemos :

    00111111111111111111111111111111 : 1073741823 en binario
    

    Ahora nos damos cuenta que se han agregado dos ceros a la izquierda. Este operador desplaza a la derecha, pero no tiene en cuenta el signo. Siempre agrega bit con el valor cero, por lo que se llama desplazamiento sin signo. Este operador suele ser más adecuado que el >> cuando queremos manipular los bits mismos, no su representación numérica.

    Operadores lógicos de bits

    editar

    Estos operadores extienden las operaciones booleanas a los enteros. Para comprender como trabajan debemos descomponer los enteros en un conjunto de bits. El operador aplicará una operación lógica bit por bit, tomando el valor de uno como verdadero y el valor de cero como falso. De un operando toma un bit y aplica la operación al bit que tiene la misma posición del segundo operando. Como resultado obtenemos otro entero.

    Operador AND de Bits

    editar

    Si ambos bits comparados son 1, establece el resultado en 1. De lo contrario da como resultado 0.

    int k = 132;   // k: 00000000000000000000000010000100
    int l = 144;   // l: 00000000000000000000000010010000  
    int m = k & l; // m: 00000000000000000000000010000000 
    
    El resultado da 128 
    

    Operador OR de Bits

    editar

    Si por lo menos uno de los dos bits comparados es 1, establece el resultado en 1. De lo contrario da como resultado 0.

    int k = 132;   // k: 00000000000000000000000010000100
    int l = 144;   // l: 00000000000000000000000010010000  
    int m = k | l; // m: 00000000000000000000000010010100 
    
    El resultado da 148
    

    Operador XOR de Bits

    editar

    Si uno de los bits comparados es 0 y el otro 1, el resultado es 1. Si ambos bits comparados son iguales, el resultado es 0.

    int k = 132;   // k: 00000000000000000000000010000100
    int l = 144;   // l: 00000000000000000000000010010000  
    int m = k ^ l; // m: 00000000000000000000000000010100 
    
    El resultado da 20 
    

    Operador NOT de Bits

    editar

    Sólo invierte los bits, es decir, convierte los ceros en unos y viceversa. Observemos que es el único de esta familia que tiene un solo operando.

    int k = 132;   // k: 00000000000000000000000010000100
    int m = ~k;    // m: 11111111111111111111111101111011 
    
    El resultado da -133 
    

    Como los enteros negativos en Java se representan con el método del complemento a dos, podemos realizar un sencillo experimento de cambiarle el signo a un número. Para realizarlo debemos aplicar a un entero el operador NOT y sumarle uno.

    int x = 123;  
    int y = ~x;   
    int z = y + 1;
    
    El resultado da -123, 
    

    Para saber más

    editar

    Operadores de asignación

    editar
    ← Operadores de bits Operadores de asignación Operador cast →


    Prácticamente lo hemos utilizado en todos los ejemplos de variables y operadores. Es el operador de asignación. Este aparece con un signo igual (=). Cambia el valor de la variable que está a la izquierda por un literal o el resultado de la expresión que se encuentra a la derecha.

    par = 2;
    perímetro  = Pi * diámetro; 
    

    En el ejemplo vemos la variable par toma el valor de 2 y perímetro el resultado de una expresión.

    Veamos un ejemplo de una instrucción tonta, que en realidad no hace nada.

    algo = algo;
    

    La variable algo toma el valor de algo; todo queda como antes. Ahora aumentemos el valor de la variable en 3 unidades.

    algo = algo + 3;
    

    Aquí la variable toma el valor que tenía mas 3 unidades. Existe una forma de simplificar la notación anterior. Es la siguiente:

    algo += 3; // equivalente a  algo = algo + 3
    

    Se juntaron el operador de suma con el de asignación. Este atajo se puede realizar para otras operaciones además de la suma. Es útil cuando la operación contiene como primer operando al valor de la misma variable en la que se almacena el resultado.

    Operadores de asignación
    Operación Operador Utilización Operación equivalente
    Suma += A += B A = A + B
    Resta -= A -= B A = A - B
    Multiplicación *= A *= B A = A * B
    División /= A /= B A = A / B
    Resto de división %= A %= B A = A % B
    Desplazamiento a la izquierda <<= A <<= B A = A << B
    Desplazamiento a la derecha >>= A >>= B A = A >> B
    Desplazamiento a la derecha sin signo >>>= A >>>= B A = A >>> B
    AND de bits &= A &= B A = A & B
    OR de bits |= A |= B A = A | B
    XOR de bits ^= A ^= B A = A ^ B

    Operador cast

    editar
    ← Operadores de asignación Operador cast (ahormado) Precedencia de operadores →


    Cada vez que realizamos una operación obtenemos un resultado. Este resultado podrá tener un tipo de dato diferente de los operandos. Veamos esto:

    public class CambioTipo {
       public static void main(String args[]){
              byte unByte = 2;
              byte otroByte = 3;
              byte result = unByte + otroByte;
       }
    } 
    

    Nos da un error en la compilación. Se debe a que se produjo un cambio de tipo en el resultado, en vez de un byte se nos apareció un int. Este es un cambio de tipo implícito.

    Pero no queremos que quede así. Podemos forzar al compilador que nos entregue un byte. Lo haremos de la siguiente forma :

    byte result = (byte)(unByte + otroByte);
    

    Estamos realizando un cambio explícito de tipo, realizado con un operador cast. Este operador aparece como el nombre del tipo a obtener entre paréntesis; siempre antepuesto al resultado que se debe modificar.

    Nos encontraremos ahora con un viejo conocido que nos ha molestado antes, es el literal descarriado:

    float f = 3.14; 
    

    Sabemos ya que nos dará un error debido a que es un literal double que trata de disfrazarse de float. Pero le daremos un cast así lo transformamos en float.

    float f = (float)3.14;
    

    De esta manera el compilador no protestará porque colocamos peras con manzanas. El operador cast se ocupó de convertir un double en un float.

    Existe un cierto peligro en la utilización indiscriminada de este operador. Observemos el siguiente programa :

    public class Int2Byte {
       public static void main(String args[]){
              int  unInt = 5000;
              byte unByte = (byte)unInt;
              System.out.println("el resultado es : " + unByte);
       }
    }
    

    Aquí intentamos meter a empujones un valor en un byte, cuyo valor es más grande de lo soportado. Pero en este caso Java tomas las cosas con indiferencia. Si ejecutamos el programa nos indicará :

    el resultado es : -120
    

    El resultado dista mucho del valor original. El operador cast se comportó como una picadora de bits. Si miramos con lupa ambos valores, nos damos cuenta de qué ocurrió:

    00000000000000000001001110001000 : un int de valor 5000 
                            10001000 : un byte de valor -120, complemento a 2
    

    Resulta que al aplicar el cast "cortamos" la variable int en los primeros 8 bits que corresponden al tamaño del byte.

    Precedencia de operadores

    editar
    ← Operador cast Precedencia de operadores Estructuras de control →


    Ya que conocimos a los operadores, vamos a tratar de colocarlos todos juntos en una sola expresión. Vamos a ver como se organizan para trabajar:

    int     j = 10;
    boolean esCierto =  j/j*j>j-j+j&&j<<j>>>j==j%j||++j<--j+j--;
    

    Civilizadamente se organizan de acuerdo al nivel del precedencia de cada uno. Primeramente proceden los unarios, luego los aritméticos, después los de bits, posteriormente los relacionales, detrás vienen los booleanos y por último el operador de asignación. La regla de precedencia establece que los operadores de mayor nivel se ejecuten primero.

    Precedencia de operadores
    Descripción Operadores
    operadores posfijos op++ op--
    operadores unarios ++op --op +op -op ~ !
    multiplicación y división * / %
    suma y resta + -
    desplazamiento << >> >>>
    operadores relacionales < > <= =>
    equivalencia == !=
    operador AND &
    operador XOR ^
    operador OR |
    AND booleano &&
    OR booleano ||
    condicional ?:
    operadores de asignación = += -= *= /= %= &= ^= |= <<= >>= >>>=

    En la tabla se muestra el nivel de precedencia de los operadores. Los de mayor nivel se encuentran arriba. Podemos ver que los últimos son los de asignación. Esto es lógico, ya que se debe calcular primeramente la expresión antes de asignar un resultado a una variable.

    Veamos unos ejemplos de cómo actúa esta regla.

    int j = 1 + 3 * 4; // resultado j = 13
    

    Desde que aprendimos aritmética básica, conocemos la regla que nos obliga a calcular la multiplicación antes de una suma. Esto también se cumple en Java.

    int j = 1 + 3 – 4;  resultado j= 0;
    

    Si todos los operadores tienen un nivel idéntico de precedencia se evalua la expresión de izquierda a derecha.

    Utilización de paréntesis

    editar

    Se utilizan para aislar una porción de la expresión de forma que el cálculo se ejecute de forma independiente. Puede forzar a una expresión a ignorar las reglas de precedencia.

    int j = 1 + 3 * 4; // resultado j = 13
    int h = (1 + 3) * 4 // resultado h = 16
    

    Tomando el primer ejemplo, forzamos al compilador a realizar la suma antes que la multiplicación.

    En este ejemplo es imprescindible la utilización de paréntesis :

    int k = 1 + (h = 3);
    

    Si quitamos los paréntesis el compilador protestará. Porque al establecer un nivel muy bajo para la asignación, procede primero la suma. Pero estamos sumando con una variable sin valor.

    Como en matemáticas, podemos anidar los paréntesis. Se comenzara a evaluar los internos hasta llegar a los externos.

    Cabe agregar que los paréntesis no disminuyen el rendimiento de los programas. Por lo tanto, agregar paréntesis no afecta negativamente al programa.


    int k = ((12 - 2) * ( 21 - 11)) / ((1+1)*(15-10)) + 1 ;
    


    1. Estructuras de control  
      1. Estructuras de selección  
        1. Sentencia if-else  
        2. Sentencia switch  
        3. Operador if-else  
      2. Estructuras de iteración  
        1. Sentencia while 
        2. Sentencia do-while 
        3. entencia for 
      3. Saltos
        1. Sentencia break 
        2. Sentencia continue 
    2. Funciones  
      1. Parámetros de una función  
      2. Cláusula return  
      3. Funciones recursivas  
    3. Programación Orientada a Objetos
      1. Clases
        1. Ejemplos de Implementación
        2. Ejercicios Prácticos
      2. Objetos
      3. Ciclo de vida de un objeto
      4. Paquetes
      5. Encapsulamiento
      6. Herencia
      7. Interfaces
      8. Polimorfismo
      9. Excepciones
    4. Almacenamiento en Java
      1. La clase String
      2. La clase StringBuffer
      3. La clase StringTokenizer
      4. Vectores (Arreglos)
      5. Colecciones (JFC)
        1. La clase ArrayList
        2. La clase Vector
        3. La clase Stack
        4. La clase Hashtable
        5. La clase HashSet
        6. La clase LinkedList
        7. La clase TreeMap
        8. La clase StringTokenizer
    5. Entrada y Salida
      1. Imprimir en Pantalla
      2. Lectura del Teclado
    6. Interfaz Gráfica
      1. Componentes Swing
      2. Eventos
      3. Applets
    7. Threads
      1. ¿Qué es un thread?
    1. Apéndices
      1. Palabras reservadas  
      2. Ejemplos prácticos
        1. Crear un PDF en Java