Programación en Java Versión para Imprimir
Programación en Java Versión para Imprimir
Sumario
Características del lenguaje
Características
Primer programa
Escribir el código
Compilar el código
Ejecutar el Código
Para saber más
Variables
Nombre de la variable
Tipo de variable
Para saber más
Literales
Literales enteros
Literales de números reales
Literales char
Literales boolean
Literales String
Ejemplos de valores literales
La palabra reservada final
Secuencias de Escape
Arrays
Operadores
Operadores aritméticos
Operadores aritméticos unarios
Operadores relacionales
Operadores booleanos
Operadores de bits
Los Bits
Desplazamientos
Desplazamiento a la izquierda
Desplazamiento a la derecha con signo
Desplazamiento a la derecha sin signo
Operadores lógicos de bits
Operador AND de Bits
Operador OR de Bits
Operador XOR de Bits
Operador NOT de Bits
Para saber más
Operadores de asignación
Operador cast
Precedencia de operadores
Utilización de paréntesis
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.
Características
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.
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.
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.
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.
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
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.
Escribir el código
Para crear el código fuente abrimos un editor, por ejemplo el Bloc de Notas de Windows o el 'vim' en
cualquier Unix, y escribimos:
/*
*/
System.out.println("Hola Mundo!");
Hay que tener cuidado de copiar el código tal cual se muestra aquí. El lenguaje Java es sensible a las
mayúsculas y minúsculas, entonces HolaMundo no es lo mismo que holamundo. Una vez terminado lo
guardamos en un archivo con el nombre de "HolaMundo.java". Esto es así porque el nombre del archivo
con extensión java tiene que ser el mismo nombre que la clase principal. (La clase principal es la que
contiene el método main). Ampliando más, todo archivo que contenga una clase declarada como " public "
tiene que tener una coincidencia entre el nombredelarchivo.java y el nombre de esa clase pública.
Compilar el código
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
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!
System.out.println("Hola Mundo");
Variables
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:
edad = 5;
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:
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 :
Para ver como se utilizan las variables, podemos modificar el primer programa. Agregaremos una variable
que contenga el texto que se mostrará en pantalla:
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)
String saludo;
System.out.println(saludo);
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) {
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) {
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!
Hola Mundo!!!
Nombre de la variable
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
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.
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.
Literales
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
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:
Para indicarle al compilador que un valor dado es de tipo long debemos incluir el sufijo L:
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
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:
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:
Literales boolean
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
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.
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;
Por ejemplo :
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:
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");
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
Las secuencias de escape son pequeñas constantes que nos brindan una gran utilidad; para comprenderlo
mejor este ejemplo (en consola):
sisi
System.out.println("Este es un ejemplo");
System.out.println("de");
System.out.println("Secuencias de Escape");
Es algo más tedio, nos ml q exitn la secuencia d escape en Java, la cuale nos ahorrarán el trabajo de la
siguiente manera:
Pero este es solo un ejemplo. ¿Qué pasa si queremos una pequeña tabulacion? Tendríamos que teclear la
barra espaciadora hasta la medi
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.
Sintaxis:
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.
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).
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)
ita_nro[it_cont] = it_cont * 2;
System.out.println(ita_nro[it_cont]);
Operadores
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
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.
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:
int j = 2147483647;
int i = j + 1;
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:
Desastroso, ¿Verdad? Veamos lo que pasó: Teníamos el valor máximo para los int:
00000000000000000000000000000001 : le sumamos 1
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:
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:
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:
float x = 5.0f;
float y = 0.0f;
float z = x/y;
System.out.println(z);
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.
int 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:
int i = 2;
int j = 2;
System.out.println(i++);
System.out.println(++j);
System.out.println(i);
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
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
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;
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
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
verdadero cuando A y B son verdaderos. Evaluación
AND && A && B
condicional.
verdadero cuando A o B son verdaderos. Evaluación
OR || A || B
condicional.
NOT ! !A verdadero si A es falso.
verdadero cuando A y B son verdaderos. Siempre evalúa
AND & A&B
ambos operandos.
verdadero cuando A o B son verdaderos. Siempre evalúa
OR | A|B
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 {
boolean x = true;
boolean y = false;
boolean a1 = x && x;
boolean a2 = x && y;
boolean a3 = y && x;
boolean a4 = y && y;
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.
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.
El resultado es falso, pero el intérprete tiene que mirar el segundo operando para saberlo.
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.
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;
Ahora deseamos saber si una variable tiene el valor "a" no importando si es mayúscula o minúscula.
char c = 'b';
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
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
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
Desplazamiento de A a la derecha en B posiciones, tiene en cuenta
>> A >> B
el signo.
Desplazamiento de A a la derecha en B posiciones, no tiene en
>>> A >>> B
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
Desplazamientos
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
int j = 33;
int k = j << 2;
Este es el resultado:
00000000000000000000000000100001 : j = 33
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).
int k = 132;
int m = k >> 2;
00000000000000000000000010000100 : k = 132
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
int x = -1;
int y = x >> 2;
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.
Modifiquemos ligeramente el programa anterior agregándole al operador un símbolo >. Nos queda de esta
manera :
int x = -1;
int y = x >>> 2;
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.
El resultado da 128
Operador OR de Bits
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 m = k | l; // m: 00000000000000000000000010010100
El resultado da 148
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 m = k ^ l; // m: 00000000000000000000000000010100
El resultado da 20
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.
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,
Operadores de asignación
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.
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:
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
Cada vez que realizamos una operación obtenemos un resultado. Este resultado podrá tener un tipo de dato
diferente de los operandos. Veamos esto:
byte unByte = 2;
byte otroByte = 3;
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.
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 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ó:
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
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;
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.
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
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.
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.
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
Obtenido de «https://es.wikibooks.org/w/index.php?
title=Programación_en_Java/Versión_Para_Imprimir&oldid=383116»
Esta página se editó por última vez el 8 jun 2020 a las 07:41.
El texto está disponible bajo la Licencia Creative Commons Atribución-CompartirIgual 3.0;
pueden aplicarse términos
adicionales.
Véase Términos de uso para más detalles.