Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programación Orientada A Objetos
Programación Orientada A Objetos
La programación orientada a objetos (POO, u OOP según sus siglas en inglés) no es más
que un paradigma de programación que viene a innovar la forma de obtener resultados.
Los objetos manipulan los datos de entrada para la obtención de datos de salida
específicos, donde cada objeto ofrece una funcionalidad especial.
Para llevar a cabo el análisis con la programación orientada a objetos hay que tener en
cuenta que los programas se codifican pensando en objetos que interactúan.
Los objetos tendrán unas determinadas propiedades y serán capaces de hacer ciertas
cosas mediante los métodos (funciones) que se les hayan definido en plantillas
denominadas clases.
Un poco de historia
JAVA fue creado como una herramienta de programación para ser usada en un proyecto
de set-top-box en una pequeña operación denominada the Green Project en Sun
Microsystems en el año 1991. El Green Team, el cual está compuesto por 13 personas
contando con James Gosling a la cabeza, trabajó durante 18 meses en Sand Hill Road
en Menlo Park en su desarrollo.
El lenguaje fue denominado de manera iniciar como Oak (nombre que fue dado gracias
a un roble que había fuera de la oficina), después cambió su denominación a "Green"
tras descubrir que Oak era una marca comercial de adaptadores de tarjetas gráficas, así
que posteriormente cambió su nombre al de JAVA.
Es frecuentada por algunos de los miembros del equipo. Lo que no está claro es de si
se trata de un acrónimo o no, aunque hay ciertas fuentes que hacen indicar que son las
iniciales de sus diseñadores: J ames Gosling, A rthur V an Hoff, y A ndy Bechtolsheim.
Otros apuestan por el siguiente acrónimo, J ust A nother V ague A cronym ("sólo otro
acrónimo ambiguo más"). La hipótesis que suena con más fuerza es que el nombre de
JAVA hace referencia a un tipo de café que se servía en un bar cercano, de ahí que el
icono sea una taza de café desprendiendo vapor. Otra pista pueden ser los 4 primeros
bytes de los archivos .class, bytes que en hexadecimal nos dan lo siguiente 0xCAFEBABE.
Y a pesar de todas estas teorías, parece que el nombre fue sacado de una lista aleatoria.
Lo que Gosling pretendía hacer es implementar una máquina virtual (MV) con una
estructura y lenguaje que fuese similar a la de C++. Entre los meses de junio y julio del
año 1994, tras una enorme sesión de varios días de John Gaga, James Gosling, Patrick
Naughton, Wayne Rosing y Eric Schmidt, el equipo reorientó la plataforma hacia el
entorno web. Previeron que la llegada de Mosaic (un navegador web) haría que internet
se convirtiese en un medio interactivo. Naughton se puso manos a la obra y creo un
prototipo de navegador web llamado "WebRunner", al que más tarde se le conocería con
el nombre de HotJAVA.
Allá por el año 1994 a los altos cargos de Sun se les hizo una demostración de HotJAVA.
La primera versión de JAVA pudo descargarse por primera vez allá por el año 1994, pero
no fue hasta el 23 de mayo del año siguiente cuando se vieron las versiones públicas de
JAVA y HotJAVA, el navegador Web. El acontecimiento fue anunciado por John Gage, el
Director Científico de Sun Microsystems. Además, el acto contó con una sorpresa, Marc
Andreessen, vicepresidente ejecutivo de Netscape, anunció que su navegador soportaría
JAVA El 9 de enero de 1996, SUN fundó el grupo JavaSoft para encargarse de toda la
parte del desarrollo tecnológico. Fue dos semanas más tarde cuando la primera versión
de JAVA fue publicada.
La promesa inicial, si recordamos era aquella que decía "Write Once, Run Anywhere",
haciendo que el lenguaje de programación sea independiente a la plataforma, y
proporcionando una máquina virtual de ejecución para aquellas plataformas más
populares logrando así que el código pudiese ser ejecutado en cualquier plataforma.
Java ha experimentado numerosos cambios desde la versión primigenia, JDK 1.0, así
como un gran incremento en el número de clases y de paquetes que forman la biblioteca
base.
Desde la versión J2SE 1.4, todo cambio en el lenguaje ha sido regulada por la "JAVA
Community Process" (JCP), la cual se basa en Java Specification Requests (JSRs) para
proponer cambios futuros a la plataforma. El lenguaje está especificado en la JLS (la
"JAVA Language Specification). Los cambios en los JLS son gestionados en JSR 901.
J2SE 1.2 (8 de diciembre de 1998) — Nombre clave Playground. Tanto esta como las
siguientes versiones fueron recogidas bajo la versión Java 2 y el nombre "J2SE" (Java 2
Platform, Standard Edition), reemplazó a JDK para diferenciar la plataforma base de
J2EE (Java 2 Platform, Enterprise Edition) y la J2ME (Java 2 Platform, Micro Edition).
Otras mejoras añadidas incluían:
J2SE 1.3 (8 de mayo de 2000) — Nombre clave Kestrel. Los cambios más destacables
fueron:
J2SE 5.0 (30 de septiembre de 2004) — Nombre clave: Tiger. (Originalmente numerado
1.5, esta notación aún es usada internamente.) Desarrollado bajo JSR 176, Tiger
incorporó un gran un número de nuevas características
No oficiales:
• NIO2.
• Java Module System.
• Java Kernel.
• Una nueva API para poder hacer usos de Días y Fechas, la cual es un reemplazo
de las antiguas clases Date y Calendar.
• Posibilidad de operar con clases BigDecimal usando operandos.
JDK 12 — se lanzó el 19 de marzo de 2019. Entre otros, Java 12 incluye una serie de
características nuevas, tales como:
A partir del código fuente el compilador genera bytecodes. Estos bytecodes son
instrucciones de código máquina para la JVM. Cada intérprete de java tiene una
implementación de la JVM.
Características de java
Robusto:
Seguro:
Portable:
Para poder desarrollar software con Java necesitamos una serie de herramientas que
nos proporciona Sun a través de su JDK (Java Development Kit).
Al igual que el lenguaje natural que utilizamos para comunicarnos, ya sea de forma oral
o por escrito, cualquier lenguaje de programación dispone de unos elementos y reglas
que deben conocerse a la hora de programar.
Los elementos del lenguaje natural nos permiten designar cosas (nombres), expresar
cualidades de esas cosas (adjetivos), expresar acciones (verbos), etc.
Aunque todos los conceptos que aprenderemos a continuación aparecen en todos los
lenguajes de programación existen diferencias en la implementación en cada uno de
ellos lo que obliga a un estudio individual en cada uno de ellos.
Identificadores:
ELEMENTO DESCRIPCIÓN
Variables - Elementos utilizados para referenciar posiciones de memoria dónde
podremos almacenar datos necesarios para el programa.
Funciones - Elementos utilizados para referenciar posiciones de memoria dónde
reside el código del programa.
Objetos - Elementos que encapsulan variables (propiedades) y funciones
(métodos) de manera que resulta más sencillo modelar los problemas
que queremos resolver simplificando el diseño de programas
complejos.
etc. - Conforme avancemos iremos conociendo más elementos de los
lenguajes de programación.
A la hora de asignar nombre a todos estos elementos hay que seguir unas reglas.
El modelo mental más sencillo que se puede tener de una aplicación informática es el
de una caja negra que recibe unos datos de entrada, los procesa y entrega unos datos
de salida representados de alguna manera.
Estos datos de entrada, los cuáles deben ser albergados en memoria y referenciados
mediante alguna variable, pueden ser de diferente naturaleza (numéricos,
alfanuméricos, etc.).
Cada lenguaje de programación dispone de unos tipos de datos básicos a los cuáles
nos tenemos que amoldar a la hora de realizar el análisis de los datos que necesitamos
en nuestra aplicación.
Variables:
Al declarar una variable en el programa estamos reservando una zona de memoria para
posteriormente albergar un dato. Existen lenguajes que necesitan que especifiquemos
el tipo de dato que se va a albergar (java) y otros que no lo necesitan (javascript).
Operadores:
Sentencias de control:
Aunque esto nos pueda asustar, el tipo de procesamiento que puede realizar es muy
básico, limitándose a:
Alterar el flujo de ejecución normal del código del programa (sentencias de salto o
bucles). También estas alteraciones estarán controladas por variables.
Hemos visto el uso de variables como mecanismo básico para almacenar y acceder a
datos en memoria. Sin embargo, en la mayoría de aplicaciones este tipo de
almacenamiento de información se queda corto por ser demasiado simple y
necesitamos a sistemas de almacenamiento más complejos, pero también más
potentes.
Excepciones:
Todos los lenguajes de programación avisan de los errores que cometamos en tiempo
de compilación, pero pocos son los que han sido diseñados para seguir avisando de
posibles errores en tiempo de ejecución. Las aplicaciones Java, gracias a que se
ejecutan bajo la supervisión de la máquina virtual (JVM), están siendo controladas
constantemente. En caso de que ocurra algún error de ejecución, se lanza una excepción
que puede ser recogida y tratada por el programador en su aplicación. De esta manera,
lo que antes solía terminar en una ejecución anormal del programa, con java puede ser
resuelto.
1.2. Clases
Las diferentes tecnologías de programación se diferencian en la manera que ofrecen de
estructurar los datos y el código que forman una aplicación.
A la hora de plantear el análisis del problema que se quiere resolver por software, todas
las tecnologías han optado por dividir dicho problema en parte más pequeñas. La
estrategia a seguir es conseguir una estructura en la que cada una de esas partes realice
una tarea única e indivisible, coordinadas por una parte principal que obtiene la
información de lo que hay que hacer de su interacción con el usuario. En la actualidad
esta interacción se realiza a través de un entorno gráfico y las órdenes se generan
mediante eventos.
Un objeto, como en la vida real, posee una serie de propiedades. Por ejemplo, digamos
que queremos crear un sistema para almacenar y organizar expedientes urbanísticos de
obra. En papel un expediente contiene los datos de la persona e información relativa a
su solicitud. Dicha persona puede tener asociados una serie de datos como nombre,
apellidos, DNI, dirección, teléfono, etc.
Una clase es una entidad que determina cómo se comportará un objeto y qué contendrá
el objeto. En otras palabras, es un plan o un conjunto de instrucciones para construir un
tipo específico de objeto.
Como se puede ver en Java las clases se definen con la palabra class seguido del
nombre por la que queremos identificarla. Vamos a explicar una serie de palabras
usadas junto a las propiedades y métodos, estas controlan de qué manera se accede a
la propiedad que acompañan:
• public: indica que la propiedad es accesible desde fuera, por ejemplo podemos
acceder a propiedades de un objeto desde los métodos de clase pero también
desde fuera de la clase usando la variable del objeto y un punto, por ejemplo
perro.colorPelo.
Hay que tener en cuenta de que la variable de un objeto no es el objeto en sí, sino una
referencia, en caso de que una función devuelva una propiedad privada con referencia a
un objeto nos arriesgamos de que más adelante el objeto pueda ser modificado y dichas
modificaciones afecten de manera inesperada al funcionamiento de otros
componentes. Para evitar la modificación de un objeto referenciado por una propiedad
privada se debe realizar una copia de dicho objeto y devolverlo, de esta manera cualquier
modificación realizada fuera de la clase no interferirá.
• byte: es un número entero que en memoria ocupa 8 bits. Sus valores van de -128
a 127.
• short: es un entero de 16 bits. Su valor mínimo es -32,768 y el máximo 32,767.
• int: es un entero de 32 bits. Su valor mínimo es -2,147,483,648 y el máximo
2,147,483,647 (inclusive). Es el tipo más usado para números enteros a menos
que haya una razón para usar otro como por ejemplo el ahorro de memoria.
• long: es un entero de 64 bits. Su valor va de -9,223,372,036,854,775,808 a
9,223,372,036,854,775,807. Obviamente se utiliza cuando int no alcanza el valor
que se requiere.
• float: es un dato en coma flotante y precisión simple. No entraremos en detalle
sobre cómo funciona, pero se utiliza para almacenar valores decimales que no
requieran gran precisión ya que pueden devolver producir cierto grado de error
en la parte decimal.
• double: dato en coma flotante de 64 bits y precisión doble. Similar a float pero
admite un mayor rango de valores, es comúnmente utilizado al tratar con valores
decimales.
• boolean: solo tiene dos valores posibles true (verdadero) y false (falso).
• char: contiene un solo carácter Unicode de 16 bits.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
}
else {
++velocidad;
Figura 1 La imagen muestra una captura de pantalla de un paquete Java con ficheros de clases y un directorio
que representa un subpaquete
Para hacer uso de clases en paquetes externos tenemos que hacer uso de su nombre
en una sentencia import o si es un uso puntual podemos usar el nombre del paquete
seguido de la clase como se ve en el siguiente ejemplo:
El principio de responsabilidad única indica que cada módulo o clase de contar con una
responsabilidad sobre una sola parte de la funcionalidad por el software y esta
responsabilidad debe estar encapsulada en su totalidad por la clase. Todos sus
servicios deben estar estrechamente alineados con esa responsabilidad. Robert C.
Martin expresa dicho principio de la siguiente forma: Una clase debe tener solo una razón
para cambiar.
abierto/cerrado es utilizado de dos maneras: las dos se basan en la herencia para poder
resolver el aparente dilema, pero tanto como sus objetos, técnicas y sus resultados son
diferentes.
Sea Φ(𝑥) una propiedad comprobable acerca de los objetivos 𝑥 de tipo 𝑇. entonces
Φ(𝑦) debe ser verdad para los objetos y del tipo 𝑆 donde 𝑆 es un subtipo de 𝑇
El ISP fue concebido para mantener a un sistema desacoplado de los otros sistemas de
los que depende, y que así resulte más fácil una refactorización, modificarlo y
redesplegarlo. El ISP es uno de los cinco principios S.O.L.I.D. del Diseño Orientado a
Objetos, similar al Principio de Alta Cohesión de GRASP.
El principio de inversión de dependencias está compuesto por los siguientes dos puntos:
A: Los módulos de alto nivel no deberían depender de los de bajo nivel. Los dos
deberían de depender de las abstracciones.
Un bosque contiene árboles, que a su vez contienen hojas, que contienen células…
Por eso se eligió la palabra “inversión”, porque rompe con esta dinámica.
Los que en principio se pretende es que no exista una necesidad de dependencia entre
unos módulos y otros, sino que dependan de abstracciones. De esta forma, nuestros
módulos pueden ser más fácilmente reutilizables.
Podemos considerar las Clases como plantillas de objetos, definen que propiedades
tienen y sus métodos, instancia una clase da como resultado un nuevo objeto. En Java
las propiedades de un objeto pueden ser de tipo primitivo o referencias a otros objetos,
en cuanto a esto último entendemos que un objeto puede estar compuesto por otros,
por ejemplo, una bicicleta está compuesta por un pedal, manillar, ruedas etc. Cada
objeto de una clase puede tener un valor propio en cada propiedad, aunque comparten
la misma funcionalidad, cada silla puede ser de un color distinto pero el hecho de que
sirve para sentarse no cambia.
A lo largo del módulo veremos el uso de objetos definidos por la clase String, esta es
una clase definida en Java y que permite almacenar y trabajar con cadenas de texto. La
peculiaridad de esta clase es que no permite la modificación del texto que almacena,
métodos como split crean un array con dos nuevas instancias de String cada una con
una copia de un fragmento del texto original. Por ello no hay porque preocuparse de
generar copias de propiedades privadas de este objeto ya que por diseño impide su
alteración. El texto englobado por comillas dobles es considerado por el compilador de
Java como un objeto String.
Coche[] referenciaArray;
// memoria para 15 coches
referenciaArray = new Coche[15];
Figura 2 Se muestra una parte de la página de descarga del kit de desarrollo en Java señalando que se deben aceptar
los términos de uso y descargar la versión apropiada a la arquitectura del procesador y sistema operativo, en este
caso Windows 64 bits.
Hemos creado una clase en la que podemos almacenar una serie de datos primitivos en
su conjunto. Dicha clase contiene una serie de miembros que almacenará cada objeto
creado a partir de la clase Factura. En el ejemplo podemos observar variables de tipo
String, String es una clase incluida en Java para representar una cadena de texto, dicho
texto es inmutable, es decir no se puede alterar, por ello la clase String implementa una
serie de métodos para operaciones como la concatenación y división de texto que
devuelven nuevas instancias.
Cada objeto Factura, es decir cada instancia de la clase, tiene su propia copia de las
variables miembro. Como hemos mencionado las variables propias de una clase
(propiedades) pueden ser de tipos primitivos (boolean, int, long, double...) o referencias
a objetos de otra clase (composición).
Como podemos comprobar, cada objeto referenciado de la clase factura contiene unos
datos diferentes para cada elemento. Es decir, cada miembro de la instancia de Factura
almacena unos datos diferentes en cada objeto.
Para compilar el programa partimos de dos ficheros con extensión .java, es importante
utilizar un editor de texto plano como el Bloc de Notas o Notepad++. Cada fichero debe
tener el nombre de la clase, en este ejemplo deben resultar como: Factura.java y
Figura 3 Ejemplo simple del comando javac para la compilación de ficheros .java javac *.java
Si lo has compilado te habrás dado cuenta de una pequeña errata en nuestro código,
para ser precisos en la línea 9 de UtilizacionFactura.java donde pone "f1.Total
= 570" falta un punto y coma al final (Figura 4):
Figura 4 Ejemplo de un error de sintaxis mostrado por el comando javac. En este caso la linea 9 de
UtilizacionFactura.java le falta un punto y coma al final.
Figura 5 Se muestra la ejecución de un programa compilado por javac con el comando java -cp . UtilizacionFactura.
Imprime en pantalla los datos de dos objetos factura distintos.
//CONSTRUCTOR DE FACTURA
public Factura()
{
//VAMOS A INICIALIZAR LOS MIEMBROS DE LA CLASE
this.NombreTitular = "sin titular";
this.ConceptoFactura = "sin concepto";
this.Precio = 0.0;
this.Iva = 0.0;
this.Total = 0.0;
}
}
Podemos observar un método con el mismo nombre que la clase Factura. Este método
lo denominamos constructor y será llamado cada vez que se cree (instanciar) un objeto,
su principal función es asignar un valor a cada variable, eso puede incluir nuevas
instancias de otras clases.
Figura 6
Como hemos visto en un objeto se pueden definir una serie de propiedades o métodos
de acceso público, ese conjunto lo denominamos parte publica o interfaz del objeto.
Otros objetos no necesitan saber cómo los demás llevan a cabo sus operaciones, solo
que la llamada a un método público produce un resultado. ( Ver diagrama de la Figura
7).
Figura 8 Diagrama del patrón de diseño Modelo-Vista-Controlador. Esta imagen representa la interacción entre los
principales componentes de una aplicación que interacciona con el usuario siguiendo el patrón de diseño MVC.
Por ejemplo, podemos tener una pantalla con los datos de una persona y botones de
Siguiente, Anterior y Guardar. La representación de los datos y la interacción con el
usuario son llevados a cabo por la vista. El usuario pulsa el botón siguiente y el
A continuación, vamos a guardar cada fichero con nuestro bloc de notas con el nombre
de la clase seguido por la extensión ".java" en la ubicación que vayamos a probar
nuestros ejemplos. Es recomendable crearnos una carpeta para poder ubicar todas
nuestras prácticas. Podemos utilizar cualquier otro editor de texto, pero es
imprescindible que sólo almacene texto plano, no nos valdrían editores de texto del
estilo Word o WordPad, ya que almacenan más información además del texto escrito,
un ejemplo de estos editores puede ser UltraEdit o algún bloc de notas "free" que se
encuentran en internet y que tienen más características que el bloc de notas tradiciones
de Windows.
Escritor.java:
public class Escritor{
//Parte privada
private String parteTexto1;
private String parteTexto2;
private int veces;
private String escribir(){
//Si no hay otra variable que se llame igual this no es
necesario
//La clase String tiene un metodo estatico para producir un
string a partir de otros tipos
String vecesString = String.valueOf(veces);
return parteTexto1 + veces + parteTexto2;
}
Main.java:
lector1.num = 1;
lector2.num = 2;
Debemos asegurarnos que el nombre de nuestro fichero "java" debe tener el mismo
nombre que nuestra clase, incluida la diferenciación de mayúsculas y minúsculas, en
nuestro ejemplo tenemos Main.java, Escritor.java y Lector.java.
Voy a crear una carpeta en la unidad C:\Ejemplo2 y almacenaré las prácticas en dicha
ubicación. En el bloc de notas seleccionaremos como Tipo: "Todos los archivos" y
escribiremos la extensión ".java" para nuestra primera clase.
Como podemos ver el objeto Escritor en su parte privada guarda el estado de cuantas
veces le han solicitado un texto y este responde en la respuesta mencionando que es
la 1ª, 2ª y 3ª vez. El objeto lector no conoce dicha parte privada y solo interesa la petición
de texto que ofrece en su parte pública. En este caso el objeto escritor también conoce
al lector, no usamos una función que devuelva el texto, sino que llama a una función del
objeto lector para responder.
Nota
1.9. Interfaces II
Herencia
Imaginemos que tenemos las instrucciones para construir una silla concreta con unas
características y usos concretos, ahora supongamos que queremos crear una silla
basada en el diseño original, pero con algunos cambios, como por ejemplo unos
reposamuñecas. Como no cobramos por horas no vamos a escribir unas instrucciones
desde cero ya que tenemos los de la silla original, simplemente copiamos las partes en
común de las instrucciones originales y añadimos nuestra parte. Este es un ejemplo
sobre el concepto de herencia de objetos, tenemos definida una clase y queremos crear
una similar, pero con ciertos cambios.
Figura 10 Un diagrama que muestra el concepto de herencia de manera simple. Tenemos una silla común, de la que
hereda una silla de escritorio y una con reposamuñecas y esta última a su vez tiene una de la que hereda con
reposamuñecas acolchado.
En este ejemplo consideramos que una "Silla de escritorio" es hija de "Silla común".
Además, de heredar de una clase normal tenemos el concepto de clase abstracta, esto
sería análogo al concepto abstracto que tenemos de una silla. Las clases abstractas no
pueden ser instanciadas, pero poseen una serie de propiedades y métodos comunes a
clases que la usan como padre. También es posible definir métodos abstractos, se
escriben como cualquier otro método, pero sin el bloque de código englobado en
corchetes. Toda clase que herede de otra con métodos abstractos debe
implementarlos.
Interfaces
Ahora que conocemos sobre la herencia podemos hablar del concepto de interfaces.
La diferencia entre una interfaz y una clase abstracta es que la interfaz solo define que
se debe implementar y propiedades constantes mientras que una clase abstracta puede
implementar métodos o definirlos abstractos, la similitud que tienen es que ambas no
pueden instanciarse.
En Java una interfaz se define con la palabra interface seguido del nombre, también es
posible que una interfaz herede de otra o varias como lo haría una clase
mediante extends:
En este ejemplo creamos una interface con los métodos que queremos que se
implementen.
Como se puede ver solo utilizamos el modificador public en una de las funciones, en
una interfaz todo método es implícitamente público, de manera que se puede omitir.
Además, todas las propiedades se consideran públicas, estáticas y constantes (public,
static y final), de la misma manera que las funciones, estas pueden ser omitidas.
Implementación de la interfaz
Si una clase quiere implementar una interfaz debe usar la palabra clave implements. Si
queremos heredar e implementar al mismo tiempo, debemos colocar primero extends
seguido del nombre de la clase y a continuación implements seguido del nombre de la
interfaz.
Sintaxis:
//Por ejemplo una función que suma uno a cada valor de una lista
de enteros
public List<Integer> addOne(List<Integer> numbers) { return
numbers .stream() .map(number -> number + 1)
.collect(Collectors.toList()); }