Download - Tutorial Java A.A
Introducción a Java Encapsulamiento en Java Método main Flujos de Control en Java Declaración de una clase en Java Control de Acceso a Miembros de Clase This, en Clases de Java Clases en Java de Utilidad Métodos de clase Origen de los Patrones de Diseño Ventajas de utilizar Patrones de diseño El Patrón Proxy El Patrón Bridge (Puente) El Patrón Iterador (Iterator) Conceptos de programación Palabras Reservadas Java
Introducción a Java
Aunque los inicios de Java se remontan a 1991, fecha en la que los ingenieros de Sun Microsystems trataban
de diseñar un lenguaje de programación para electrodomésticos, Java se introduce como lenguaje de
programación a finales de 1995.
Java, según lo describe Sun, es un lenguaje simple, orientado a objetos, distribuido, interpretado, robusto,
seguro, de arquitectura neutra, portable, de altas prestaciones, multitarea y dinámica. Muchos de estos conceptos se irán explicando en sucesivos capítulos. La verdad es que java es un lenguaje muy completo y en
el que casi todo depende de todo. Es por eso por lo que su aprendizaje se orienta de forma iterativa: a partir
de una visión muy general se va refinando en sucesivas iteraciones.
Existen distintos programas comerciales que permiten desarrollar código en Java. Nosotros prestaremos atención a Sun Microsystems que distribuye gratuitamente dos productos:
Java(tm) Development Kit (JDK): conjunto de programas y librerías que permiten compilar y ejecutar
programas escritos en Java. Incorpora además un depurador (Debugger) para ejecutar
parcialmente un programa, revisar los valores de variables, etc. con el objetivo de corregir errores de codificación.
Java Runtime Environment (JRE): se trata de una versión reducida del JDKdestinada únicamente a la
ejecución de código Java.
Los programas en Java se construyen con clases. Instanciando estas clases se podrán crear cualquier
cantidad de objetos. Se puede pensar en una clase como en una plantilla para construir objetos. Las clases estarán compuestas por dos tipos demiembros: los campos, o datos de la clase, y los métodos, o acciones
que se pueden realizar sobre los datos.
Ahora podemos comenzar a sumergirnos en Java. Veamos para ello un programa muy sencillo, el clásico
ejemplo del programa que imprime "Hola Mundo": HolaMundo.java
Holamundo.java declara una clase llamada HolaMundo . Los miembros de la clase aparecen entre llaves. Esta clase tendrá un miembro, el método denominando main . Este método se ejecuta cuando ejecutamos la clase
como aplicación.
El único parámetro del método main es un vector de objetos String que son los argumentos con los que se
invocará al programa desde la línea de órdenes. voidindica que el método main no devuelve ningún valor. La única sentencia que contiene el método main invoca al método println en el objetoout de la clase System.
Esta sentencia imprime una cadena con terminación de salto de línea en el flujo de salida estándar.
Encapsulamiento en Java
Imaginemos que se crea una clase, una docena de programadores tienen acceso a dicha clase y la utilizan a
discreción, posteriormente dicha clase comienza a comportarse de una manera inesperada debido a que los valores que algunas variables han tomado no fueron anticipados y todo comienza a desmoronarse. Para
corregir el problema se crea una versión más nueva de dicha clase y listo.
Bueno, a esto le llamamos flexibilidad y capacidad de mantenimiento, ambas son características y beneficios de la programación Orientada a Objetos (OO) pero para que una clase pueda cumplir dichas funciones los
programadores debemos de hacer algo. Imaginemos que creamos una clase con variables de instancia
públicas a las cuales podemos acceder sin problemas desde fuera de la misma clase...
Analizando el código anterior podemos darnos cuenta de que las variables enteras tipo y clase son públicas y pueden ser accedidas directamente a través de una instancia de la clase MiClase, esto compila sin ningún
problema, digamos que es 'legal', sin embargo, ¿qué pasa si ingresamos un valor que no se supone debe de
tener una variable (en este caso el -5 que le asignamos a tipo)?, simplemente no hay nada que nos detenga
para hacerlo. La única manera de proteger el código es escribiendo un método que nos permita regular los valores que cada variable puede tener y escondiendo las variables para que no se pueda acceder a ellas de
manera directa, esto es el principio básico de encapsulamiento.
Si se desea flexibilidad, buen mantenimiento y extensibilidad, nuestro diseño en el código debe de incluir encapsulamiento, para ello debemos de hacer lo siguiente:
1. Mantener las variables de instancia protegidas (puede ser con un modificador de acceso, p.ej.,
private).
2. Hacer métodos de acceso públicos para forzar al acceso a las variables por medio de dichos métodos en lugar de acceder directamente.
3. Utilizar las convenciones de código para los nombres de los métodos, p. ej., set y get.
El ejemplo anterior modificado para un buen encapsulamiento quedaría así:
Si nos fijamos un poquito, en el método setTipo() no existen validaciones para prevenir que un valor no válido sea asignado a la variable, sin embargo, el proveer de un método de este tipo desde el diseño inicial de la
aplicación nos permite posteriormente modificar el comportamiento de la misma sin afectar los métodos
utilizados, tal vez en un futuro se desee que dicha variable solamente pueda tener uno entre un rango de
valores y se podrán aplicar posteriormente los cambios sin que haya repercusiones negativas.
Método main en Java
El método main proporciona el mecanismo para controlar la aplicación. Cuando se ejecuta una clase Java el
sistema localiza y ejecuta el método main de esa clase. Veamos un ejemplo
Los argumentos del array de cadenas son los "argumentos de la clase". El programa imprimiría por pantalla
estos argumentos. Así para realizar una posible ejecución de la aplicación escribiríamos en la línea de
comandos: java imprime hola que tal estas
Obteniéndose como resultado:
hola que tal estas
El método main debe ser public, static y void(no devuelve nada)
Flujos de Control en Java
Un programa java está compuesto por una serie de sentencias. Las dos sentencias básicas en el lenguaje Java se reflejan en la siguiente tabla:
sentencias de declaración que son las que hemos estudiado para declarar variables y constantes.
sentencias de expresión
Expresión de asignación, a = b+c;
Formas prefijas o posfijas de ++ y --, contador++;
Llamadas a métodos, Objeto1.mimetodo();
Expresiones de creación de objetos Sentencias de control
Estas últimas son las que controlan el flujo de ejecución del programa. Normalmente el orden de ejecución de
sentencias es el mismo en el que están escritas. Sin embargo, las sentencias de control de flujo introducen bifurcaciones en la ejecución del programa. A continuación estudiaremos en detalle cada uno de los tipos de
sentencias.
if-else
La sentencia if-else nos permite elegir entre dos alternativas de flujo diferentes. La ejecución del programa dependerá del resultado de evaluar la expresión booleana,
si el valor de expresion_booleana es true se ejecutará el bloque_de_sentencias1, en caso contrario, si hay
parte else, se ejecuta el bloque_de_sentencias2. La cláusulaelse es opcional.
Si queremos que un programa compruebe la edad de una determinada persona para saber si es menor de edad o no, bastaría con preguntar en una sentencia if-else si la variable edad, que es donde tenemos
almacenada la edad de la persona, es menor que dieciocho. En caso afirmativo, aplicaremos un descuento del
5% y en caso contrario del 15%.
Supongamos que además de saber si alguien es mayor o menor de edad queremos aplicar un nuevo descuento para jubilados. Podemos cambiar el problema y anidar sentencias if-else.
switch La sentencia switch selecciona entre un grupo de sentencias en función de la evaluación de una expresión. Su
formato sería:
si se encuentra una etiqueta case cuyo valor_integral coincida con el de la expresiónselector se trasfiere el
control a su correspondiente bloque_de_sentencias. En caso de que ningún valor coincida se ejecuta el bloque_de_sentencias correspondiente a la etiqueta default.
En la sentencia switch no es necesario escribir break al final de cada case. Si falta la sentencia break el
código de la siguiente sentencia case se ejecutará hasta que se encuentre un break. Tal es el caso del
siguiente ejemplo, donde se traduce una nota numérica a su correspondiente nota verbal.
Vemos como cuando la nota es un 7 al no tener un break continúa la ejecución hasta el siguiente case, el 8,
imprimiendo NOTABLE. Lo mismo sucede con el SOBRESALIENTE.
Todas las etiquetas case deben ser expresiones constantes, es decir, literales o identificadores declarados
como static final e inicializados con un valor constante. for
Esta sentencia se usa para realizar un bucle a lo largo de un rango de valores desde el principio hasta el final,
Lo habitual es usar for cuando queremos recorrer todo un rango de valores de una variable. De esta
forma, expresion_inicial indica el punto de partida para hacer iteraciones, expresion_incremento cómo se va a
ir incrementando la variable yexpresion_booleana expresa que condición debe cumplirse para que el bucle for acabe.
Al principio el contador i lo inicializamos a 1 pues el uno es un divisor para cualquier número. Iremos
incrementando i de uno en uno y calculando el módulo de la división del numero entre i. La condición de salida
del bucle es cuando el contador sea menor o igual que la mitad del número, pues no habrá divisores con un valor mayor.
El bucle for sólo acaba cuando se cumple la condición de salida o cuando en elbloque_de_sentencias se
encuentra una sentencia break. Sin embargo, debido a que se utiliza para iterar a lo largo de un rango de
valores, romper el bucle es de mal estilo. while y do-while
Con la sentencia while se repite el bloque_de_sentencias hasta que la expresión booleana sea falsa. Un
bucle while sería:
El bucle while puede no ejecutarse nunca pues la expresion_booleana puede ser falsa la primera vez que se evalúa. Como hay veces que se desea que el bucle se ejecute al menos una vez, en Java tenemos también la
instrucción do-while:
aquí la expresión booleana se evalúa al final por lo que bloque_de_sentencias se ejecuta al menos una vez.
break y continue
Las sentencias break y continue se utilizan dentro de los bucles y modifican el flujo natural de los mismos. La sentencia break provoca la salida inmediata del bucle que estemos ejecutando, sin realizar la ejecución del
resto de las sentencias. La sentencia break se puede usar tanto en bucles como en bifurcaciones. El siguiente
uso de break en el bucle while nos garantiza que j no será nunca negativo, pues en ese caso romperá el bucle
y continuará con la ejecución normal:
La sentencia continue finaliza la iteración que en ese momento se está ejecutando, salta al final del cuerpo
del mismo y evalúa la expresión booleana que controla dicho bucle. Se suele usar un continue para saltarse
un elemento del rango de valores que recorre el bucle. El uso de continue en el siguiente código evita que se
produzca una división por cero al calcular el valor de aux.
return
La sentencia return termina la ejecución de un método y devuelve al invocador el control de flujo del
programa. En el caso de que la función devuelva alguna variable, este valor se deberá poner a continuación
del return, return <valor>. El siguiente ejemplo nos enseña un uso de la sentencia return para determinar si un número es positivo:
EsPositivo.java
Declaración de una Clase en Java
Vimos como los elementos principales de una clase son sus atributos (datos) y sus métodos (código para
manipular los datos). Veamos una clase simple, Publicacion que podríamos utilizar para almacenar los datos
sobre nuestra colección bibliográfica:
El nombre de la clase, Publicacion debe ser un identificador válido en Java y por convención, empieza por letra
mayúscula. Una declaración de clase crea un nombre de tipo en Java. De esta forma las referencias a objetos Publicacion se pueden declarar con un simple:
Las variables de una clase se llaman campos. La clase Publicacion tiene tres campos, idPublicacion que
identifica de forma unívoca cada publicación, titulo que es el título de la publicación y autor que ha firmado la publicación.
Podríamos definir un campo propietario. Con este campo indicaríamos el propietario del libro. Sería útil, si sólo
vamos a almacenar nuestras publicaciones, que el valor de este campo lo compartan todas los objetos que
podamos definir a partir de esta clase. Calificaríamos la declaración de este campo con la palabra reservada
static:
Control de Acceso a Miembros de una Clase en Java
Cuando se definió la clase Publicacion, el campo idPublicacion se pensó para que se generase de forma
automática y de forma coherente. Por tanto cualquier modificación externa sobre este campo podría dejar al objeto en un estado inconsistente, y podríamos tener dos objetos con el mismo identificador. Queremos por
tanto que este campo sólo se pueda leer y no pueda ser modificado por ningún otro objeto. Para ello se
"oculta" este campo y se proporciona un método público para poder acceder a su valor:
¿Qué hemos conseguido? Ahora para acceder al valor del campo idPublicacion será necesario utilizar el método id. Y la única forma de modificar este campo será por medio de métodos internos a la
clase Publicacion .
Estos mecanismos que regulan el acceso se denominan métodos de acceso y se resumen en la siguiente tabla:
Método Descripción
private Un miembro privado es accesible sólo para la clase en la que está definido.
protected La propia clase, las subclases y todas las clases dentro del mismo paquete tienen acceso a los miembros calificados
con este método de acceso.
public Todas las clases tienen acceso a los miembros públicos de la clase.
package Sólo las clases del mismo paquete que la clase tienen acceso a los miembros
En los constructores de las clases, se pueden utilizar especificadores de acceso para indicar que objetos pueden crear ejemplares de su clase: private si ninguna clase puede crear un objeto de su clase, sólo se
podrá crear por medio de métodos públicos de la clase, protected cuando sólo las subclases pueden crear
objetos, public si cualquiera puede crear objetos de esta clase y package-access cuando sólo desde los
objetos pertenecientes al mismo paquete se pueden crear objetos de esa clase.
This, Clases Java
Hay ocasiones en las que resulta útil referirse al objeto desde el que se está ejecutando un método. En esas
ocasiones se puede usar la referencia especial de objeto this, pero cuidado, siempre dentro de un método no
estático.
Esta referencia se suele usar para pasar una referencia al objeto actual como un parámetro para otros métodos. La siguiente llamada añadiría el objeto a una relación de publicaciones prestadas:
Se usa this cuando un atributo está oculto por una declaración de variable o parámetro. Por ejemplo:
En el segundo constructor titulo y autor están ocultos por los parámetros con el mismo nombre. Para garantizar que accedemos al campo adecuado en lugar de al parámetro del método, le colocamos el
prefijo this
Clases en Java de Utilidad
Las clases de utilidad son estructuras de datos, es decir, estructuras que nos sirven para la organización de
los datos. En este apartado veremos las más comunes que nos servirán, en las siguientes lecciones, para
poder crear estructuras más complejas.
Array
Un vector (array) es una manera de agrupar un conjunto de valores bajo un mismo nombre. La manera de acceder a aquellos es mediante un número denominadoíndices. Todos los valores pertenecientes a un vector
tendrán el mismo tipo.
La declaración de un tipo vector en Java puede hacerse de dos maneras:
int vector[];
int[] vector;
En ambos casos obtendríamos un vector de enteros. Aunque ambas formas son correctas, utilizaremos la
segunda manera, que separa la declaración de tipo del nombre de la variable.
Los vectores en Java se tratan como objetos de una clase predefinida. Los arrays pueden asignarse a objetos
de la clase Object y los métodos de Object pueden utilizarse con vectores. Por tanto deben crearse llamando
a un constructor con new, aunque el constructor tenga una sintaxis totalmente distinta a la estudiada hasta
ahora:
int vector[] = new int[30];
También se pueden inicializar con valores entre llaves separados por comas:
Esta declaración es lo mismo que crear el vector por medio de un constructor e ir asignándole los valores uno a uno:
Como puede observar, se accede a los elementos de un vector con los corchetes y uníndice que varía de 0 a
la longitud del vector menos uno. Esto también es válido cuando queremos consultar los valores del vector:
Vectores.java
Se puede acceder al número de elementos de un vector con la variable miembro implícita length. Rescribiendo el programa anterior:
Conviene recordar que los vectores son objetos porque, a la hora de pasar argumentos a una función, se
pasarán por referencia.
Un detalle importante es el valor con el que se inicializan lo elementos del vector. Cuando se crea el vector los
elementos se inicializan con el valor por defecto del tipo correspondiente (cero para valores numéricos,
carácter nulo para char, false paraboolean, null para String y referencias).
Los argumentos del array de cadenas son los "argumentos de la clase". El programa imprimiría por pantalla
estos argumentos. Así para realizar una posible ejecución de la aplicación escribiríamos en la línea de
comandos:
java imprime hola que tal estas
Obteniéndose como resultado:
hola que tal estas
El método main debe ser public, static y void(no devuelve nada)
Métodos de Clase
Los métodos de una clase constituyen la lógica de la clase, es decir, contienen el código que manipula el
estado del objeto. Además constituyen el mecanismo utilizado para implementar los mensajes entre objetos. Quiere decir, cuando un objeto se comunica con otro por un mensaje lo hace por medio de la invocación al
método correspondiente del objeto. Y el mecanismo para invocar un método en java es por medio de las
referencias usando el operador de la siguiente forma:
referencia.metodo (parametros);
Declaración de los Métodos
Veamos la forma de declarar un método. La estructura general de una declaración tiene dos partes, la
declaración y el cuerpo del método.
La Declaracion_del_metodo proporciona información sobre su nombre, la accesibilidad del método, el número de parámetros que recibe, etc. El Cuerpo_del_metodo contiene el conjunto de sentencias que manipula los
datos de cada objeto.
Sobrecarga de métodos
Cada método tiene una "firma" por así decirlo, que son su nombre, el tipo y número de sus parámetros. Existe
una característica para tener dos métodos (ó constructores) con el mismo nombre. Esta característica se denominasobrecarga de métodos.
Hemos estudiado la construcción de distintos constructores para una clase y hemos puesto como ejemplo el
caso de una clase Publicacion. Veamos lo implementado hasta el momento y cómo los constructores nos dan
un ejemplo de sobrecarga de métodos:
El compilador resolverá que constructor debe ejecutar en cada momento en función del número de
parámetros y su tipo. Si se llama al constructor sin parámetros se ejecutará el primer constructor y en caso de hacerlo con dos parámetrosString se ejecutará el segundo.
Nota: El concepto de sobrecarga de métodos se puede aplicar siempre que los parámetros sean diferentes, bien por su
tipo, bien por que el número de parámetros de un método o otro es diferente. Hay que tener cuidado con los tipos: int,
byte y short ya que aunque son tipos diferentes, si hacemos la llamada aún método con un número entero no sabría a cual
de los métodos llamar, ya que un entero puede ser considerado de las tres formas. Con double y float no pasa, porque
acordaros que hemos de forzar a que Java entienda un decimal como float, sino lo entiende como double.
Origen de los Patrones de Diseño
Los patrones surgen al realizar un esfuerzo mental para generalizar la solución a problemas diversos y
aparentemente independientes. Por tanto, cualquiera puede encontrar y utilizar sus propios patrones de diseño a través de la experiencia. Además, los patrones son un buen vehículo para transmitir dicha
experiencia a otras personas.Veamos un ejemplo:
Supongamos que hemos terminado una aplicación de generación de facturas. Una parte de nuestro diseño
contiene el siguiente diagrama de clases:
En otra ocasión diseñamos una aplicación de gestión de un almacén de repuestos, donde nos encontramos con este diagrama de clases en una parte del diseño:
Se trata de dos estructuras muy similares, pero no es esto lo que nos sugiere la existencia de un patrón. Sino
el papel que juegan estas estructuras en el diseño. Y, en efecto, dicho papel se repite en ambos casos:
Factura es algo que se compone de varias Líneas de factura, y además, las líneas de factura no tienen sentido sin la existencia de la Factura.
Almacén es algo que se compone de Repuestos, y además, los repuestos requieren la existencia de un
Almacén.
Hemos dado con un patrón de diseño, se trata de una idea: un objeto que almacena otros objetos, y éstos últimos no tienen sentido sin su "almacén". Se trata del patrón "Continente-Contenido":
Pero no es el único patrón que podemos encontrar:
Línea de Factura es un objeto que se compone necesariamente de Concepto, Cantidad y Precio..
Repuesto es un objeto que se compone necesariamente de Pieza, Garantía y Precio.
Aquí hay otra idea que se puede generalizar: un objeto que se desglosa en otros objetos. Podríamos llamarlo
el patrón "Objeto-componente":
Cuando nos enfrentamos a un nuevo problema intentaremos aplicar los patrones que conozcamos, y esto no
es una sugerencia, sino el comportamiento natural de todo ser humano. Por otra parte, es muy importante
tener en cuenta que los patrones no sólo surgen y se aplican a diseños diferentes. Un mismo patrón puede aplicarse varias veces en un mismo diseño.
Ventajas de utilizar Patrones de diseño
Como hemos dicho, los patrones son meras ideas que no están exentas de sus ventajas e inconvenientes. El
uso continuado de estas ideas pone de manifiesto, de manera natural, dichas ventajas e inconvenientes, de
manera que se conocen a priori. Por tanto, es posible elegir el patrón mas adecuado a nuestras necesidades, pero no eludir sus inconvenientes. Esto es algo a sopesar en cada caso, no obstante, el criterio para decidir la
bondad de un patrón con respecto a un problema es bien conocido. Estos son los aspectos de un patrón que
se deben evaluar:
Resistencia al cambio: se debe elegir el patrón que facilite lo más posibles futuros cambios. Los cambios en un diseño no son probables, son seguros, se producen con toda seguridad. A la hora de
diseñar una solución a un problema es conveniente abstraer el problema concreto a otro más
genérico y resolver este último. Los patrones consiguen precisamente esto.
Reutilización: este aspecto requiere una aclaración importante. La reutilización de código resulta prácticamente imposible. En cambio, los diseños son mucho más reutilizables, pero ni siquiera tanto
como las propias ideas. Se debe tender a reutilizar las ideas. Por eso, cuando hacemos un diseño
debemos pensar en que nos debe ser útil para futuros proyectos, en su esencia o filosofía, no en su
estructura o implementación. Así, lo conveniente es buscar patrones nuevos en diseños nuevos,
documentarlos y almacenarlos como una parte importante de nuestra experiencia. Son como una "álbum de fotos" de nuestros viajes.
En general, la gran ventaja del uso de patrones es que minimizan el riesgo de generar un mal diseño y
permiten comunicar experiencias entre diseñadores.
El Patrón Proxy
Este patrón consiste en interponer un intermediario (Proxy) entre un objeto y los demás que lo utilizan. Se diferencia del patrón Adaptador en que el objeto "adaptado" solamente puede ser manipulado a través del
objeto Proxy.
Se suele utilizar para implementar comportamientos "vagos" (lazy). Por ejemplo, si tenemos muchos objetos
imagen en un documento, se tardaría mucho tiempo en abrir el documento al cargar las imágenes de disco. Para evitarlo podemos sustituir los objetos imagen por objetos proxyImagen, con el mismo interfaz, pero que
solamente cargan la imagen cuando se va a visualizar.
Debemos insistir en dos aspectos que caracterizan el patrón Proxy:
El objeto Apoderado tiene el mismo interfaz que el objeto "Protegido". Para facilitar esto se puede
derivar el objeto Apoderado de la misma clase padre que el objeto "Protegido", pero no es
absolutamente necesario.
El objeto "Protegido" solamente puede ser manipulado por su correspondiente Apoderado.
Un ejemplo típico de aplicación del patrón proxy es el de un editor de documentos. El editor podrá incluir
imágenes y dibujos complejos, y se plantea el problema de recuperar todos estos costosos objetos cada vez
que se abre el documento. La aplicación del patrón proxy soluciona el problema definiendo un
"representante", que ocupe su lugar, hasta que sea necesario cargarlos.
El Patrón Bridge (Puente)
Como sabemos, una abstracción puede tener diferentes implementaciones. El mecanismo de herencia permite
que la implementación de una abstracción evolucione sin modificar significativamente el diseño. Esto es cierto
mientras la abstracción en sí misma (básicamente, su interfaz) no evolucione. Es decir, no se puede modificar
independientemente una implementación y la abstracción a la que está ligada. Este patrón consigue que esto sea posible.
La parte importante del esquema son las clases Abstracción yClaseObjetoImplementor. Los descendientes de Abstracción son "evoluciones" de la abstracción que pueden o no mantener la implementación. Al mismo
tiempo, los descendientes de ClaseObjetoImplementador son "evoluciones" de la implementación
independientes de la evolución de Abstracción.
El esquema estático es el siguiente:
El Patrón Iterador (Iterator)
Este patrón se utiliza en relación a objetos que almacenan colecciones de otros objetos, por ejemplo, las
listas. El uso de un objeto Iterador permite recorrer los elementos del agregado independientemente de su organización. Si todos los objetos agregado (listas, árboles, etc) generan un objeto Iterador con el mismo
interfaz resulta muy fácil operar con ellos y se facilitan los cambios de implementación.
El objeto agregado puede crear objetos Iterador para la implementación concreta de dicho agregado.
Diferentes implementaciones, diferentes iteradores. A partir de entonces, un objeto cliente puede manipular el
agregado únicamente a través del iterador. Si cambiamos la implementación del agregado (por ejemplo, la
lista pasa a ser un árbol), el objeto cliente no resulta afectado. Se trata de un patrón muy común y ampliamente utilizado. En el caso de las listas, podríamos recorrerla sin exponer su estructura interna,
permitiendo así diferentes tipos de listas (listas normales, con vectores, etc) y diferentes tipos de iteradores:
Conceptos de Programación
Un proceso es la ejecución de un programa, es decir, los datos e instrucciones están cargados en la memoria
principal, ejecutándose o esperando a hacerlo.
Un proceso no tiene porqué estar siempre en ejecución. Puede pasar por diferentes estados:
Preparado: Un proceso preparado es el que está preparado para ejecutarse. Sólo le "falta" la CPU En Ejecución: Un proceso en ejecución es un proceso que "tiene" CPU, se está ejecutando
Bloqueado: Un proceso bloqueado está esperando que ocurra un suceso antes de poder "usar" la CPU. Dicho suceso suele ser una operación de Entrada / Salida: pulsar una tecla, leer de disco... Pero
también puede ser que esté esperando a que otro proceso haga algo
1. Creación del proceso. Está preparado para ejecutarse
2. El proceso se ejecuta en CPU 3. El proceso espera a que ocurra un suceso y se bloquea
4. Ocurre el suceso por el que esperaba el proceso. Está preparado para ejecutarse
5. El proceso "sale" de la CPU
6. Fin de la ejecución del proceso
No es necesario cumplir todos los pasos, por ejemplo, podría ser que un proceso hiciera los pasos 1-2-6.
Desde el punto de vista del Hardware, dependiendo del número de CPU's, un sistema puede ser:
Sistema Monoprocesador
Sistema Multiprocesador o Sistema fuertemente acoplado
o Sistema débilmente acoplado
Como su nombre indica, un sistema monoprocesador es aquel en el que sólo hay una CPU; y como todos
habréis imaginado, un sistema multiprocesador es el que tiene varias CPU's. Éste último se divide en 2
tipos. Los sistemas fuertemente aclopados, en los que hay memoria común y los débilmente acoplados, en los que no hay memoria común. Un ejemplo de los fuertemente acoplados es un PC con varios
procesadores, y otro de los débilmente acoplados es una red de ordenadores.
Desde el punto de vista del Software, también hay diferentes tipos de sistemas, atendiendo a cómo se
ejecutan los procesos:
Sistema de Multiprogramación
Sistema de Multiprocesamiento
La Multiprogramación consiste en que todos los procesos se ejecuten en la misma CPU. Esto se consigue
mediante la intercalación de la ejecución de los procesos.
En Multiprocesamiento cada proceso se ejecuta en una CPU. En este caso hay paralelismo real en la
ejecución de los procesos.
Además de la programación imperativa o secuencial y la programación concurrente, hay otros
paradigmas o enfoques de la programación.
La programación imperativa se centra en la transformación que hay que realizar para procesar los datos, pasando estos a un segundo plano. En cambio, la programación orientada a objetos gira en torno a un
nuevo concepto: el objeto. Éste comprende tanto procesos como datos. Aunque pueda parecer más
complejo, este tipo de programación se asemeja a la forma que tiene el ser humano de ver el mundo, frente a
la programación imperativa que está orientada a la máquina. Para entenderlo mejor, un objeto es "una cosa con límites definidos", como por ejemplo, una pelota, que tiene características (datos como tamaño o color),
asociadas a unas operaciones (procesos como botar o lanzar) aplicables sobre el objeto. Otras operaciones no
son válidas. No puedes beberte una pelota... aunque el mundo es muy raro y hay de todo. Otra característica
importante de la programación orientada a objetos es la herencia. Este mecanismo se utiliza para estructurar el programa en forma jerárquica.
La programación declarativa es otra visión de la programación, en la que no se describe cómo obtener los
resultados, sino qué es lo que debemos obtener. Se divide en 2 tipos, la programación lógica y
la programación funcional.
Hace unos años, cuando todavía no existían los entornos gráficos, ni el hardware que los soportara, todo se
hacía en un entorno de consola. Al abrir una ventana de msdos en windows, o una consola de comandos en
unix... entran escalofríos sólo de pensar que las cosas eran antes "tan frías". Eso si, no se colgaban de vez en
cuando sin saber porqué. Primero Apple copiando de Xerox, y después Microsoft copiando de Apple, crearon los entornos visuales, con lo que vino la revolución multimedia y se disparó el negocio de la informática.
Dichos entornos visuales constan de una interfaz gráfica "más amigable", además de ofrecernos un amplio
abanico de posibilidades. No hay que creer que los entornos multitarea aparecieron con entornos visuales en
que se puede "tener abiertas muchas ventanitas". UNIX siempre ha sido multitarea, desde el modo consola.
Ahora vamos a hacer un pequeño repaso de las arquitecturas existentes dentro del mundo de la informática. Cuando en los años 60 se empezaron a comercializar los ordenadores, disponibles sólo para empresas debido
a su alto coste, se utilizabansistemas centralizados o mainframes, que tenían diferentes consolas para dar
acceso a múltiples usuarios. Todo el trabajo lo realizaba el mainframe. En los años 80 surgió el PC, con un
precio más asequible. Nacieron los sistemas en red que permiten interconectar ordenadores de diferentes características compartiendo recursos. El siguiente paso fueron los sistemas distribuidos en los que hay
diferentes estaciones interconectadas, aunque el usuario no necesita conocer su ubicación, como sucede en
los sistemas en red. El acceso a los recursos es transparente, es decir, se accede a los recursos como si
fueran locales, aunque no lo sean. También existen sistemas paralelos, que constan de varios procesadores operando conjuntamente.
Una vez aclarados ciertos conceptos, es hora de empezar con el curso de Metodología de la Programación.
Palabras Reservadas en Java
En este capítulo hay un listado de palabras reservadas Java orientado a objetos. Las palabras reservadas son identificadores, pero como su nombre indica, estas palabras están reservadas, y no se pueden usar como identificadores de usuario.
abstract
assert
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
enum
extends
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
try
void
volatile
while