Conceptos Fundamentales de Programación en Java: Estructuras, Control y POO
Estructuras de Datos Simples en Java
Variables
Una variable es una referencia a un objeto; por lo tanto, se puede declarar de la siguiente manera:
int i;
int j = 25;
long num = 30;
boolean f, t; // Corrección: 'long boolean' no es un tipo válido en Java
Button buttonOK;
Constantes
final int meses = 12;
final String primerdia = "lunes";
Clases String y StringBuffer
Las clases String
y StringBuffer
están orientadas a manejar cadenas de caracteres. La clase String
se utiliza para cadenas de caracteres constantes, es decir, que no pueden cambiar. La clase StringBuffer
permite que el programador cambie la cadena insertando, borrando, entre otras operaciones.
Ambas clases pertenecen al paquete java.lang
, por lo tanto, no es necesario importarlas.
"Hola".length();
Métodos de la clase String
A continuación, se describen dos formas de crear objetos de la clase String
:
String str1 = "Hola";
String str2 = new String("Hola");
Conversión de Tipos (Casting)
Casting
Por ejemplo, si se define un int
y luego se maneja como long
:
int entero;
long enterolargo;
enterolargo = (long) entero;
ACLARACIÓN: No lo convierte directamente, sino que una clase puede representar a otra.
Los boolean
no aceptan ningún casting, mientras que el casting de char
a byte
o short
puede resultar en un valor negativo, ya que char
no contempla el signo.
Estilo de Código y Formato
Tabulación
La forma exacta de la tabulación (espacios o tabuladores) no se especifica; no obstante, la unidad de tabulación debería ser de cuatro espacios.
Longitud de Línea
Evitar líneas con una longitud no mayor de 80 caracteres (idealmente, no más de 70 caracteres), ya que pueden cortarse y algunas IDEs no las manejan adecuadamente.
Ruptura de Líneas (Wrapping Lines)
Cuando una expresión no cabe en una única línea, debe dividirse siguiendo estos principios generales:
- Romper después de una coma.
- Romper antes de un operador.
- Preferir las rupturas de alto nivel a las de bajo nivel.
- Alinear la nueva línea con el inicio de la expresión al mismo nivel que la línea anterior.
Si las reglas anteriores resultan en un código confuso o demasiado pegado al margen derecho, entonces tabular solo con 8 espacios.
Tantas normas solo por la longitud de la línea (mayor a 80 caracteres) pueden parecer innecesarias e inmanejables. Se recomienda adoptar las que mejor se adapten a su forma de trabajar y documentar el código.
Sentencias de Control de Flujo
Sentencia switch
La sentencia switch
permite ejecutar una de varias acciones, de acuerdo al valor de una expresión, la cual debe ser de tipo char
, byte
, short
o int
. Es una sentencia para decisiones múltiples que elimina el if
anidado.
Cada vez que un caso continúa con el siguiente (es decir, no incluye una sentencia break
), se debe añadir un comentario donde iría la sentencia break
.
Sentencia for
for (inicialización; condición; actualización);
Sentencia while
while (condición)
{
sentencias;
}
Una sentencia while
vacía debe tener el siguiente formato:
while (condición);
Sentencia do-while
do {
sentencias;
}
while (condición);
Arreglos (Arrays)
Un array (o arreglo) es una estructura de datos simple que permite almacenar un conjunto de objetos del mismo tipo, ya sean primitivos u objetos.
Los arrays son objetos en Java; su uso correcto implica los siguientes pasos:
- Declarar el array:
int[] numeros;
- Crear el array:
numeros = new int[4];
- Inicializar los elementos del array:
numeros[0] = 278;
Los arrays se pueden declarar, crear e inicializar en una misma línea, del siguiente modo:
int[] numeros = {278, -45, 15, -125};
Clase Vector
java.util.Vector
Jerarquía de clases:
java.lang.Object
java.util.AbstractCollection
java.util.AbstractList
java.util.Vector
Interfaces implementadas:
Serializable
Cloneable
Iterable
Collection
List
RandomAccess
Para usar la clase Vector
, debe importar el paquete java.util
al principio del archivo del código fuente.
Para instanciar la clase Vector
, se pueden utilizar distintos constructores:
Vector vector = new Vector();
Cuando se utiliza el constructor sin argumentos, la capacidad inicial es diez; al llenarse, aumenta de tamaño duplicándose.
Vector vector = new Vector(capacidadInt, incrementoInt);
Vector vector = new Vector(5, 3); // Inicialmente tiene capacidad para 5 elementos, cuando se llena aumenta de a 3 lugares.
La menor dimensión es Vector(1,1)
, ya que de esta forma almacena un elemento, se llena y agrega solo de a un lugar.
Métodos Importantes de la Clase Vector
v.insertElementAt(8, 2);
: insertarsize()
: cantidad de elementos que guarda un vectorcapacity()
: dimensión actual del vector
Se pueden eliminar todos los elementos de un vector llamando al método removeAllElements()
.
Se puede eliminar un elemento concreto llamando al método v.removeElement(elemento);
Se puede eliminar dicho elemento si especificamos su índice: v.removeElementAt(2);
Acceso a los Elementos de un Vector
En lugar de usar un índice como en un Array, se utiliza el método elementAt(índice)
. Por ejemplo, v.elementAt(4)
sería equivalente a v[4]
si v
fuese un array.
Enumeration
permite acceder a los elementos de una estructura de datos de forma secuencial; su código es:
public interface Enumeration {
boolean hasMoreElements();
Object nextElement();
}
La función miembro elements()
de la clase Vector
devuelve un objeto de la clase VectorEnumerator
que implementa la interfaz Enumeration
y debe definir las dos funciones hasMoreElements()
y nextElement()
.
Vectores vs. Arrays: ¿Cuál Utilizar?
Los arrays ofrecen tres ventajas sobre Vector
:
- Pueden almacenar directamente tipos de datos primitivos.
- Sus elementos pueden ser accedidos sin necesidad de mensajes, lo que hace el código más rápido que si se usara un
Vector
. - Como los arrays son tipados, ofrecen una verificación en tiempo de compilación que
Vector
no tiene. Si se almacena accidentalmente un objetoString
en unVector
donde se tienen almacenados objetosInteger
, Java lo permite. Sin embargo, Java generaría un error de compilación si se intenta almacenar unString
en un array de referencias aInteger
.
Sin embargo, los arrays también presentan algunas desventajas sobre Vector
:
- Son de tamaño fijo y no pueden crecer.
- No ofrecen un conjunto de operaciones tan ricas como la clase
Vector
(a través de métodos comoinsertElementAt()
).
Programación Orientada a Objetos (POO) en Java
Normalmente, las definiciones de clases incluyen los siguientes elementos:
- Modificador de acceso: especifica la visibilidad de la clase para otras clases.
- Palabra clave de clase:
class
indica a Java que el bloque de código siguiente define una clase. - Campos de instancia: se refiere a las variables y constantes utilizadas por los objetos de la clase.
- Constructores: son los métodos que se invocan para instanciar la clase y tienen el mismo nombre que esta.
- Métodos de instancia: definen las funciones que pueden actuar sobre los datos de una clase.
- Campos de clase: contienen variables y constantes que pertenecen a la clase y que todos los objetos de la clase comparten (
static
). - Métodos de clase: son los métodos que se utilizan para controlar los valores de los campos de la clase.
Creación de Objetos
Por ejemplo, si se tiene la clase Persona
, el objeto se crea de la siguiente manera:
Persona unoNuevo; // Declara la referencia al objeto
unoNuevo = new Persona(); // Crea el espacio en memoria y devuelve una instancia de la clase Persona.
La primera línea crea una referencia a un objeto llamado unoNuevo
de la clase Persona
. La segunda línea crea el objeto.
También se puede definir en una sola línea, de la siguiente manera:
Persona unoNuevo = new Persona();
El operador new
invoca al método constructor de la clase; es decir, la llamada al operador new
devuelve una referencia al objeto nuevo.
Atributos de Objeto y Encapsulamiento
unoNuevo.nom = "José";
Si el atributo es declarado con el modificador private
(aplicando el concepto de encapsulamiento), la asignación directa solo podrá realizarse dentro de la misma clase. Fuera de la clase, se deberá utilizar el método de instancia público setXxx()
. En este caso, sería:
unoNuevo.setNom("José");
Los tipos de valores que se definen para un atributo pueden ser:
- Primitivos: los tipos de datos que vienen con el lenguaje Java, como
int
. - Objetos: los definidos por el lenguaje, como
String
oInteger
, o bien definidos por el usuario. Por ejemplo: dentro de la claseAuto
, el atributovolante
puede ser de tipoVolante
.
Concepto de Paquetes (Packages)
Java, como lenguaje, está organizado en paquetes (packages). Un package es una agrupación de clases. Existe una serie de packages incluidos en el lenguaje.
Jerarquía de Clases de Java (API)
Es importante distinguir entre lo que significa herencia y package. Un package es una agrupación arbitraria de clases, una forma de organizar las clases. La herencia, sin embargo, consiste en crear nuevas clases basándose en otras ya existentes.
En la actualidad, se cuenta con la API Java™ 2 Platform Standard Edition, más conocida como Java 2.
Herencia
Si una clase deriva de otra (extends
), hereda todas sus variables y métodos. La clase derivada puede añadir nuevas variables y métodos y/o redefinir los variables y métodos heredados.
Métodos Constructores
Se utiliza new
para la creación de un objeto, lo cual implica la invocación de un método constructor de la clase a la que el objeto pertenece.
Por ejemplo:
Persona unoNuevo = new Persona(); // Invoca al constructor por defecto
Persona otroNuevo = new Persona("José"); // Invoca al constructor que recibe un parámetro.
El Constructor this
Es posible pensar que this
es un objeto; en realidad lo es, pero uno muy especial: es una referencia al objeto que se acaba de crear con new
y cuyo constructor se está ejecutando.
this.nombre = nombre;
El Constructor super()
Sirve para acceder desde un constructor al constructor de la superclase. Al igual que this()
, super()
debe ser la primera invocación que aparezca en el constructor.
Concepto de Interfaces
Una interfaz debe ser considerada como un contrato entre un proveedor de servicios y sus clientes.
Es una clase abstracta que no puede ser instanciada y que debe ser implementada en otra clase.
Una clase puede implementar más de una interfaz, representando una forma alternativa de la herencia múltiple.
A su vez, una interfaz puede derivar de otra o incluso de varias interfaces, en cuyo caso incorpora todos los métodos de las interfaces de las que deriva.
modificador interface nombreI {
modificador tipoDevuelve nombreDelMetodo(parametros);
}
La interfaz define los métodos abstractos, es decir, solo su firma, pero no su código. La clase que la implementa define el método con la misma firma, estableciendo cómo lo aplica.
Manejo de Excepciones en Java
Las excepciones son el mecanismo que utiliza la Java Virtual Machine (JVM) para el manejo de errores leves que pueden producirse durante la ejecución de una aplicación y que podrían detener su ejecución.
Las excepciones se crean en el momento en que se produce una situación anormal o excepcional en tiempo de ejecución, como por ejemplo, la utilización de una referencia con valor null
.
El lenguaje Java provee la sintaxis necesaria para el control de excepciones dentro de un programa. Los operadores son:
try
: observa el comportamiento de un determinado bloque de código que es susceptible de arrojar excepciones.catch
: en caso de que el bloque observado portry
arroje una excepción,catch
captura el error, permitiendo algún tipo de procesamiento del mismo y la posibilidad de tomar un curso correctivo.finally
: bloque de sentencias que se ejecutan siempre que exista el bloquetry
, aunque este no arroje excepción. Generalmente, se utiliza para liberar recursos, como conexiones de bases de datos o cierre de archivos abiertos.throw
: fuerza el lanzamiento de una excepción.throws
: informa que un determinado método puede arrojar algún tipo de excepción.
Entrada/Salida (I/O) Básica en Java
Básicamente, el paquete java.io
define dos tipos principales: los streams de entrada o salida (InputStream
y OutputStream
) y los Reader
y Writer
. Los streams se encargan de manejar datos en forma de bytes, mientras que los Reader
y Writer
lo hacen en forma de caracteres.
Entre los objetivos que cumplen todas las clases del paquete, se pueden nombrar:
- Acceso a redes de datos
- Comunicación asíncrona entre hilos (pipes)
- Acceso a archivos en disco
- Acceso a datos en memoria
- Parseo de datos
- Serialización / deserialización de objetos
- Acceso a buffers de memoria
- Lectura y escritura de datos en la consola
Lectura y Escritura en Consola
Para esto, la clase System
tiene un InputStream
en el atributo estático in
(generalmente conectado al teclado), y define además dos atributos estáticos del tipo PrintStream
denominados out
y err
. El primero es la salida estándar del sistema (generalmente conectado a la pantalla), y el segundo es específico para mensajes de error (también por defecto dirigidos a la pantalla).
Lectura y Escritura de Archivos en Disco
La lectura y escritura de archivos es muy común en aplicaciones de escritorio. También se utiliza en APIs como Log4j, que sirve para escribir en distintos dispositivos de salida los estados por los que pasa la ejecución de un programa, también conocido como logging.
Organización de Archivos y Estructura del Código
Un archivo consiste en secciones que deberían estar separadas por líneas en blanco y un comentario opcional que identifique cada sección. Los archivos de más de 2000 líneas son demasiado largos y deberían evitarse.
Estructura de Ficheros de Código Fuente Java
Cada archivo de código fuente Java contiene una única clase o interfaz pública. Cuando una clase pública tiene clases privadas e interfaces asociadas, se pueden colocar en el mismo archivo de código fuente que la clase pública. La clase pública debería ser la primera clase o interfaz en el archivo.
Los archivos de código fuente Java tienen la siguiente ordenación:
- Comentarios iniciales
- Sentencias
package
eimport
- Declaraciones de clase e interfaz
Sentencias package e import
La primera línea que no sea un comentario es una sentencia package
. Después, puede haber sentencias import
. Por ejemplo:
package edu.modelo;
import java.util.List;
El primer componente de un nombre de paquete único se escribe en letras ASCII minúsculas y es uno de los nombres de dominio de nivel superior (actualmente .com
, .edu
, .gov
, .mil
, .net
, .org
o uno de los códigos de país de dos letras, como se especifica en el estándar ISO 3166).
Declaraciones de Clase e Interfaz
Variables de Clase (Estáticas)
El orden correcto de aparición de las variables es: primero las variables públicas (public
), luego las protegidas (protected
), después las de paquete (sin modificador de acceso) y, por último, las privadas (private
).
Variables de Instancia
Primero las variables públicas (public
), luego las protegidas (protected
), después las de paquete (sin modificador de acceso) y, por último, las privadas (private
).
Métodos
Los métodos deberían estar agrupados por funcionalidad en lugar de por ámbito o accesibilidad. Por ejemplo, un método estático privado puede estar entre dos métodos de instancia públicos. El objetivo es facilitar la lectura y comprensión del código.
Formato de Declaraciones de Clase e Interfaz
Ningún espacio entre el nombre del método y el paréntesis (
que abre su lista de parámetros.
La llave de apertura {
aparece al final de la misma línea que la sentencia de declaración.
La llave de cierre }
comienza una línea nueva tabulada para coincidir con su sentencia de apertura correspondiente, excepto cuando es un bloque vacío que se presenta como {}
.
Uso de Líneas en Blanco
En los siguientes casos, siempre se deben usar dos líneas en blanco:
- Entre secciones de un archivo fuente.
- Entre definiciones de clases e interfaces.
En los siguientes casos, siempre se debe usar una línea en blanco:
- Entre métodos.
- Entre las variables locales de un método y su primera sentencia.
- Antes de un comentario de bloque o de una sola línea.
- Entre las secciones lógicas de un método, para mejorar la legibilidad.
Uso de Espacios en Blanco
Los espacios en blanco deben usarse en los siguientes casos:
Una palabra clave seguida por un paréntesis debe estar separada por un espacio. Por ejemplo: