Explora Libros electrónicos
Categorías
Explora Audiolibros
Categorías
Explora Revistas
Categorías
Explora Documentos
Categorías
Unidad 3.
Programación Orientada a Objetos
Lenguaje de Programación II Prof. Melvyn Quiñones
INDICE
1. Introducción ......................................................................................................................... 4
Origen de la POO ............................................................................................................................. 5
Conceptos fundamentales .............................................................................................................. 6
Características de la POO ................................................................................................................ 8
Tipos de POO ................................................................................................................................. 10
Algunos lenguajes orientados a objetos ....................................................................................... 10
2. Objetos y clases .................................................................................................................. 11
Objeto............................................................................................................................................ 11
Clases............................................................................................................................................. 11
Instancias....................................................................................................................................... 12
3. Modificadores de Acceso .................................................................................................... 16
Modificador de acceso por defecto (default) ............................................................................... 16
Modificador de acceso privado (private) ...................................................................................... 17
Modificador de acceso protegido (protected) .............................................................................. 18
Modificador de acceso público (public) ........................................................................................ 18
Modificadores que no son de acceso ............................................................................................ 19
4. Tipos de atributos ............................................................................................................... 20
Variables de instancia ................................................................................................................... 20
Variables de clase (static) .............................................................................................................. 21
Constantes o variables finales (final) ............................................................................................ 23
Clases contenedoras o Wrappers.................................................................................................. 24
5. Clases estándar de java ....................................................................................................... 24
Objetos de la clase Character ........................................................................................................ 24
Objetos de la clase String .............................................................................................................. 25
Operaciones con instancias de la clase String ........................................................................... 25
Otros métodos para trabajar con objetos de la clase String ..................................................... 27
Clase Array..................................................................................................................................... 27
Objetos de la clase Array ........................................................................................................... 27
Operaciones con Arrays ............................................................................................................. 28
Array de objetos ........................................................................................................................ 30
Arrays multidimensionales ........................................................................................................ 31
6. Métodos en Java ................................................................................................................. 33
Return y Void................................................................................................................................. 34
Recursión ....................................................................................................................................... 36
Sobrecarga de métodos (Overload) .............................................................................................. 36
Tipos de métodos .......................................................................................................................... 37
Métodos de instancia ................................................................................................................ 37
Métodos de clase....................................................................................................................... 38
1. Introducción
La Programación Orientada a
Objetos (POO, en español; OOP,
según sus siglas en inglés) es 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.
Está basada en varias técnicas del sexenio: herencia, cohesión, abstracción, polimorfismo,
acoplamiento y encapsulamiento.
La identidad es una propiedad de un objeto que lo diferencia del resto; dicho con otras
palabras, es su identificador (concepto análogo al de identificador de una variable o una
constante).
Origen de la POO
Conceptos fundamentales
La POO es una forma de programar que trata de encontrar una solución a estos
problemas. Introduce nuevos conceptos, que superan y amplían conceptos antiguos ya
conocidos. Entre ellos destacan los siguientes:
Clase: Una clase es una especie de "plantilla" en la que se definen los atributos y
métodos predeterminados de un tipo de objeto. Esta plantilla se crea para poder crear
objetos fácilmente. Al método de crear nuevos objetos mediante la lectura y
recuperación de los atributos y métodos de una clase se le conoce como instanciación.
Herencia: Por ejemplo, herencia de la clase C a la clase D, es la facilidad mediante la
cual la clase D hereda en ella cada uno de los atributos y operaciones de C, como si
esos atributos y operaciones hubiesen sido definidos por la misma D. Por lo tanto,
puede usar los mismos métodos y variables registrados como "públicos" (public) en C.
Los componentes registrados como "privados" (private) también se heredan pero se
mantienen escondidos al programador y sólo pueden ser accedidos a través de otros
métodos públicos. Para poder acceder a un atributo u operación de una clase en
cualquiera de sus subclases pero mantenerla oculta para otras clases es necesario
registrar los componentes como "protegidos" (protected), de esta manera serán
visibles en C y en D pero no en otras clases.
Características de la POO
Abstracción
Encapsulamiento
Significa reunir todos los elementos que pueden considerarse pertenecientes a una misma
entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión (diseño
estructurado) de los componentes del sistema. Algunos autores confunden este concepto
con el principio de ocultación, principalmente porque se suelen emplear conjuntamente.
Polimorfismo
Herencia
Las clases no se encuentran aisladas, sino que se relacionan entre sí, formando una
jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de
todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el
encapsulamiento, permitiendo a los objetos ser definidos y creados como tipos
especializados de objetos preexistentes. Estos pueden compartir (y extender) su
comportamiento sin tener que volver a implementarlo. Esto suele hacerse habitualmente
agrupando los objetos en clases, y estas en árboles o enrejados que reflejan un
comportamiento común. Cuando un objeto hereda de más de una clase, se dice que hay
herencia múltiple; siendo de alta complejidad técnica por lo cual suele recurrirse a la
herencia virtual para evitar la duplicación de datos.
Modularidad
Principio de ocultación
Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone
una "interfaz" a otros objetos que específica cómo pueden interactuar con los objetos de
la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por
quien no tenga derecho a acceder a ellas; solamente los propios métodos internos del
objeto pueden acceder a su estado. Esto asegura que otros objetos no puedan cambiar el
estado interno de un objeto de manera inesperada, eliminando efectos secundarios e
interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo
a los datos internos del objeto de una manera controlada y limitando el grado de
abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos.
Recolección de basura
Tipos de POO
Basada en prototipos. Es soportado en Javascript, Python y Ruby. No hay clases, solo hay
objetos. El mecanismo para la reutilización está dado por la clonación de objetos. Se crean
directamente los objetos y cuando se quiere generar otro con la misma estructura se usa
clonación. Una vez clonado si queremos podemos agregar los campos y métodos
necesarios. Un objeto prototípico es un objeto que se utiliza como una plantilla a partir de
la cual se obtiene el conjunto inicial de propiedades de un objeto. Cualquier objeto puede
ser utilizado como el prototipo de otro objeto, permitiendo al segundo objeto compartir
las propiedades del primero.
Simula (1967) es aceptado como el primer lenguaje que posee las características
principales de un lenguaje orientado a objetos. Fue creado para hacer programas de
simulación, en donde los "objetos" son la representación de la información.
Smalltalk (1972 a 1980) es posiblemente el ejemplo canónico, y con el que gran parte de la
teoría de la programación orientada a objetos se ha desarrollado, aunque existen otros
lenguajes orientados a objetos que son igual de importantes:
2. Objetos y clases
Objeto
Rutinas o métodos: Es una componente de un objeto que lleva a cabo una determinada
acción o tarea con los atributos. En principio, todas las variables y rutinas de un programa
de Java deben pertenecer a una clase. De hecho, en Java no hay noción de programa
principal y las subrutinas no existen como unidades modulares independientes, sino que
forman siempre parte de alguna clase.
Clases
Convención de los programadores en Java: los identificadores de las clases deberían ser
simples, descriptivos y sustantivos y, en el caso de nombres compuestos, con la primera
letra de cada uno en mayúsculas. Es conveniente utilizar las palabras completas y evitar
los acrónimos, a menos que la abreviatura sea mucho más utilizada que la forma no
abreviada como en URL o HTML.
Instancias
Aunque el término a veces se emplea de una forma imprecisa, un objeto es una instancia
de una clase predefinida en Java o declarada por el usuario y referenciada por una
variable que almacena su dirección de memoria. Cuando se dice que Java no tiene
punteros simplemente se indica que Java no tiene punteros que el programador pueda
ver, ya que todas las referencias a objeto son de hecho punteros en la representación
interna.
En general, el acceso a los atributos se realiza a través del operador punto, que separa al
identificador de la referencia del identificador del atributo (idReferencia.idAtributo). Las
llamadas a los métodos para realizar las distintas acciones se llevan a cabo separando los
identificadores de la referencia y del método correspondiente con el operador punto:
(idReferencia.idMetodo(parametros))
// Metodos
public double da() {
return this.euros;
}
public void pone(double x) {
this.euros = x;
}
}
Gráficamente, una clase puede representarse como un rectángulo, tal y como se muestra
la representación gráfica de la clase Precio:
Para poder trabajar con objetos se tendrá que seguir un proceso de dos pasos. Lo primero
que debe hacer el programa es crear una referencia o puntero de la clase Precio con el
identificador p. De forma similar a cómo se declara una variable de un tipo primitivo, la
declaración del identificador de la referencia se realiza con la sintaxis:
identificadorClase identificadorReferencia;
// En el ejemplo anterior: Precio p;
A continuación, la grafica de la creación de la referencia p:
El resultado de la ejecución del código anterior son dos nuevas instancias de la clase
Precio referenciados respectivamente por p y q. El atributo euros de cada una de las
nuevas instancias de la clase Precio es accesible a través del identificador de la referencia
y del operador punto (p.euros y q.euros). Los métodos da y pone pertenecientes a la clase
Precio son accesibles a través del identificador de la referencia y del operador punto
(p.da() y p.pone(56.8) y q.da() y q.pone(75.6), respectivamente). En el caso de los
métodos, la instancia mediante la cual se realiza la llamada correspondiente actúa como
un parámetro o argumento implícito del método.
Si se asigna una referencia a otra mediante una sentencia de asignación, no se copian los
valores de los atributos, sino que se tiene como resultado una única instancia apuntada
por dos referencias distintas. Por ejemplo:
q = p; // Ahora p y q referencian al mismo objeto
En este caso ¿qué ocurre con la instancia referenciada previamente por q? Dicha instancia
se queda sin referencia (inaccesible). Esto puede ser un problema en algunos lenguajes de
programación, como es el caso de Pascal o de C, que utilizan variables dinámicas y que
necesitan liberar explícitamente el espacio en memoria reservado para las variables que
van a dejar de ser referenciadas. La gestión dinámica de la memoria suele ser una tarea
engorrosa para el programador y muy dada a la proliferación de errores de ejecución. Para
evitar tales inconvenientes, Java permite crear tantas instancias como se desee (con la
única limitación de la memoria que sea capaz de gestionar el sistema), sin que el
programador tenga que preocuparse de destruirlas o liberarlas cuando ya no se necesiten.
El entorno de ejecución de Java elimina automáticamente las instancias cuando detecta
que no se van a usar más (cuando dejan de estar referenciadas). A este proceso se le
denomina recogida o recolección de basura (garbage collection).
El operador instanceof
No podemos usar instanceof para tratar de comprobar dos clases de diferentes jerarquías.
Por ejemplo, NO podemos hacer la comparación con un objeto hijo de la clase Math con
un hijo de la clase String. Esto provocaría un error de compilación.
3. Modificadores de Acceso
Como su nombre indica, los modificadores de acceso en Java ayudan a restringir el alcance
de una clase, constructor, variable, método o miembro de datos. Hay cuatro tipos de
modificadores de acceso disponibles en Java:
Cuando no se especifica ningún modificador de acceso para una clase, método o miembro
de datos, se dice estar teniendo modificador de acceso default por defecto.
Los miembros de datos, clase o métodos que no se declaran utilizando ningún modificador
de acceso, es decir, que tengan un modificador de acceso predeterminado, solo son
accesibles dentro del mismo paquete.
En este ejemplo, crearemos dos paquetes y las clases en los paquetes tendrán los
modificadores de acceso predeterminados e intentaremos acceder a una clase de un
paquete desde otra clase del segundo paquete.
El modificador de acceso privado se especifica con la palabra clave private. Los métodos o
los miembros de datos declarados como privados solo son accesibles dentro de la clase en
la que se declaran. Cualquier otra clase del mismo paquete no podrá acceder a estos
miembros. Las clases e interfaces no se pueden declarar como privadas (private).
En este ejemplo, crearemos dos clases A y B dentro del mismo paquete p1. Declararemos
un método en la clase A como privado e intentaremos acceder a este método desde la
clase B y veremos el resultado.
class A {
private void mostrar() {
System.out.println("Java desde Cero");
}
}
class B{
public static void main(String[] args) {
A obj= new A();
//tratando de acceder al método privado de otra clase
obj.mostrar();
}
}
Salida:
Error:(15, 12) java: mostrar() has private access in p1.A
En este ejemplo, crearemos dos paquetes p1 y p2. La clase A en p1 es public, para acceder
a ella desde p2. El método que se muestra en la clase A está protegido y la clase B se
hereda de la clase A y, a continuación, se accede a este método protegido creando un
objeto de clase B.
// Programa Java para ilustrar
// el modificador protected
package p1;
public class A {
El modificador de acceso público tiene el alcance más amplio entre todos los demás
modificadores de acceso.
Las clases, métodos o miembros de datos que se declaran como públicos son accesibles
desde cualquier lugar del programa. No hay restricciones en el alcance de los miembros
de datos públicos.
public class A {
public void mostrar(){
System.out.println("Dios te bendiga");
}
}
4. Tipos de atributos
Los atributos, también llamados “datos o variables miembro” son porciones de
información que un objeto posee o conoce de sí mismo. Una clase puede tener cualquier
número de atributos o no tener ninguno. Se declaran con un identificador y el tipo de dato
correspondiente. Además los atributos, tienen asociado un modificador que define su
visibilidad según se muestra en la siguiente tabla.
Variables de instancia
// Declaracion de metodos . . .
}
Genera dos instancias de la clase Precio como muestra la figura siguiente. En este caso,
cada una de las dos instancias, p y q, de la clase Precio tiene una variable de instancia
euros propia. Las respectivas llamadas al método pone para cada instancia
(p.pone(56.8) y q.pone(75.6)), permiten asignar un valor a las variables de instancia
correspondientes.
Otro ejemplo. En la declaración de la clase Fecha se incluyen tres atributos (dia, mes y
anho) que son variables de instancia:
public class Fecha {
// Declaracion de atributos o variables miembro
private int dia;
private int mes;
private int anho;
// Declaracion de metodos . . .
}
Cada una de las instancias de la clase Fecha reserva espacio en memoria para cada una de
las variables de instancia como muestra la siguiente figura:
Las variables de instancia pueden declararse como public o como private y pueden
pertenecer a cualquiera de los tipos de datos primitivos de Java o bien, a otra clase
existente en Java o declarada por el usuario. En principio, la única limitación para el
número de variables de instancia que puede declarar una clase es el espacio libre
disponible en la memoria del sistema que ejecute el programa.
Las variables de clase son atributos diferentes de las variables de instancia. Las variables
de clase implican una sola zona de memoria reservada para todas las instancias de la
clase, y no una copia por objeto, como sucede con las variables de instancia. Para
diferenciarlas de éstas en el código fuente de Java, las variables de clase se distinguen con
el modificador static en la declaración del atributo correspondiente. Por defecto (si no se
indica la palabra static), el atributo declarado se considera variable de instancia.
Durante la ejecución del programa, el sistema reserva un único espacio en memoria para
cada variable estáticas o de clase independientemente del número de instancias creadas
de una clase. Esta reserva se produce la primera vez que encuentra dicha clase en el
código, de forma que todas las instancias pertenecientes a una clase comparten la misma
variable de clase. A diferencias de las variables globales fuera de la POO, las variables de
clase garantizan la encapsulación.
Las variables de clase sirven para almacenar características comunes (constantes) a todos
los objetos (número de ruedas de una bicicleta) o para almacenar características que
dependen de todos los objetos (número total de billetes de lotería). Por ejemplo, la clase
CuentaBancaria tiene una variable de instancia, saldo, y una variable de clase,
totalCuentas.
public class CuentaBancaria {
// Atributos o variables miembro
public double saldo; // Variable de instancia
public static int totalCuentas=0; // Variable de clase
// Declaraciones de metodos...
}
Las variables de clase se emplean cuando sólo es necesaria una copia por clase que,
además, esté accesible por todas las instancias de la clase a la que pertenece. En este
caso, al ser un atributo public y static, puede accederse directamente a la variable de clase
(totalCuentas) a través de una instancia (c1 o c2) o de la clase en sí (CuentaBancaria). Un
atributo estático puede ser accedido desde cualquier instancia de la clase, ya que es
miembro de la propia clase.
public class PruebaCuentaBancaria {
public static void main (String [] args) {
CuentaBancaria c1 = new CuentaBancaria();
c1.totalCuentas++;
System.out.println("Total cuentas: " + c1.totalCuentas);
CuentaBancaria c2 = new CuentaBancaria();
c2.totalCuentas++;
System.out.println("Total cuentas: " + c2.totalCuentas);
// Acceso a traves de la clase:
CuentaBancaria.totalCuentas++;
System.out.println("Total cuentas: " +
CuentaBancaria.totalCuentas);
}
}
Para operar con variables de clase también podemos implementar métodos en la clase.
Por ejemplo el siguiente método incTotalCuentas incrementa en una unidad el valor de la
variable de clase totalCuentas.
public static void incTotalCuentas() {
totalCuentas++;
}
Las variables de clase pueden declararse como public o como private y pueden pertenecer
a cualquiera de los tipos de datos primitivos de Java o bien, a otra clase existente en Java
o declarada por el usuario. En principio, la única limitación para el número de variables de
clase que puede declarar una clase es el espacio libre disponible por el sistema que
ejecute el programa.
Una clase puede contener atributos de valor constante o variables finales. Este tipo de
atributo se indica con la palabra reservada final. Las variables finales se suelen declarar
además como variables de clase (static final) por razones de ahorro de memoria ya que, al
no modificar su valor sólo suele ser necesaria una copia en memoria por clase (y no una
por instancia). Por ejemplo, en la clase Circulo:
public class Circulo {
// Atributos o variables miembro
private static final double PI = 3.141592; // Constante de
clase
private double radio;
La palabra reservada final indica que el atributo debe comportarse como una constante,
es decir, no puede ser modificada una vez declarada e inicializada. Por otro lado, se puede
separar la declaración de la inicialización de la variable final, realizándose ésta más tarde.
En este caso, el valor asignado a la variable final puede hacerse en función de otros datos
o de llamadas a métodos, con lo que el valor de la constante no tiene porqué ser el mismo
para diferentes ejecuciones del programa.
03- Programación Orientada a Objetos Página 23
Lenguaje de Programación II Prof. Melvyn Quiñones
En Java existen una serie de clases predefinidas equivalentes a los tipos primitivos
denominadas wrappers, clases contenedoras o envoltorios. Como muestra la siguiente
tabla el identificador de cada una de estas clases es el mismo que el del tipo primitivo
correspondiente pero con la letra inicial en mayúsculas (salvo int - Integer y char -
Character). Cada una de estas clases declaran un conjunto de métodos de gran utilidad.
El uso de estas clases puede ser especialmente interesante para realizar determinadas
operaciones mediante los métodos que implementan. En la siguiente sección se analiza el
uso de la clase Character.
La clase predefinida Character permite trabajar con instancias a las que se les puede
asociar un único carácter Unicode. Esta clase incluye un conjunto de métodos que facilitan
la manipulación de datos de tipo primitivo char.
Character a1;?
a1 = new Character('A');
Character a2 = new Character('B');
String es una clase predefinida y especial de Java definida en la librería o paquete java.lang
y orientada a manejar cadenas constantes de caracteres. Una instancia de la clase String
es inmutable, es decir, una vez que se ha creado y se le ha asignado un valor, éste no
puede modificarse (añadiendo, eliminando o cambiando caracteres). El siguiente código
muestra diferentes ejemplos de creación de referencias e instancias de la clase String:
String cortesia = new String("Buenos dias");?
// O bien, al ser una clase muy habitual en la forma abreviada:
String saludo = "Hola";?
// O tambien:?
String despedida;?
despedida = "Adios";
Al ser un objeto, una instancia de la clase String no sigue las normas de manipulación de
los datos de tipo primitivo con excepción del operador concatenación. El operador +
realiza una concatenación cuando, al menos, un operando es un String. El otro operando
puede ser de un tipo primitivo. El resultado es una nueva instancia de tipo String. Por
ejemplo:
"casa" + "blanca" // Genera "casablanca"
"capitulo" + 5 // Genera "indice5"
5 + "capitulo" // Genera "5capitulo"
"x" + 2 + 3 // Genera "x23"
2 + 3 + "x" // Genera "5x": cuidado con la prioridad de los
operadores
2 + (3 + "x") // Genera "23x"
También puede emplearse el operador +=, de forma que la sentencia a+=b es equivalente
a la sentencia a = a+b.
La comparación de dos objetos String no se realiza con el operador igualdad (==), ya que
se compararían las referencias, sino que se realiza con el método equals, de forma que
cadena1.equals(cadena2) devuelve true si cadena1 y cadena2 hacen referencia a un
mismo valor. Los métodos más importantes de la clase String se resumen en la siguiente
tabla:
Para visualizar por pantalla el contenido de un objeto String pueden emplearse los
métodos print y println de la clase estándar System.out.
if (saludo.equals(despedida))
System.out.println(saludo);
else
System.out.println(despedida);
La longitud de una cadena puede obtenerse con el método length perteneciente a la clase
String que devuelve un valor entero que indica el número de caracteres que componen la
cadena:
String despedida = "Adios";?
int longitud = despedida.length(); // longitud toma el valor 5
longitud = "Hasta luego".length(); // longitud toma el valor 11
Una cadena de longitud igual a 0, que no contiene ningún carácter, se denomina cadena
vacía y se representa como "". Por otro lado, el método charAt devuelve el carácter cuya
posición indica el parámetro de la llamada, teniendo en cuenta que las posiciones se
indican con valores enteros y que el 0 corresponde al primer carácter de la cadena.
char c = despedida.charAt(2); // c toma el valor 'i'
El método substring, con los parámetros enteros inicio y fin, devuelve una nueva
subcadena contenida en la de origen. Si sólo se le indica el primer parámetro, devuelve la
cadena a partir del carácter indicado hasta el final de la cadena original. Por ejemplo:
String despedida = "Adios";
?String s1 = despedida.substring(1,3); // s1 toma el valor "di"
String s2 = despedida.substring(1); // s2 toma el valor "dios"
Clase Array
Otra clase estándar muy empleada en Java es la clase array o vector. El término español
vector para referirse a esta clase de objetos puede dar lugar a confusión ya que, como se
verá más adelante, existe una clase Vector predefinida en Java. En este caso y sin que sirva
de precedente, es conveniente emplear el término inglés array.
Un objeto de la clase predefinida array permite representar una secuencia lineal y finita
de elementos del mismo tipo. Estos elementos pueden ser de tipo primitivo o
pertenecientes a otras clases. Los arrays son objetos con características propias. Además
del conjunto de elementos del mismo tipo, un objeto de tipo array almacena en memoria
una constante numérica entera que representa el número de elementos o tamaño del
array.
Como ocurre con los demás objetos, la ejecución de la sentencia anterior sólo crea la
referencia del array, pero no el array en sí.
De esta manera, se reserva espacio para todos los elementos del array: 5 valores enteros.
La creación de una referencia/puntero y del array de enteros al que apunta puede llevarse
a cabo de forma simultánea en la misma sentencia:
Puede accederse al tamaño en el código fuente del programa mediante el atributo length
que devuelve el número de elementos de un array (identificadorArray.length).
El acceso a cada elemento del array se realiza con el identificador de la instancia, la pareja
de corchetes y su índice (un valor numérico entero), considerando que el primer elemento
tiene índice 0:
Por lo tanto, a un array de n elementos le corresponde siempre un índice válido dentro del
intervalo [0 ... n-1]. Un error muy común es intentar acceder al elemento de índice n, que
no existe (se producirá un error de ejecución out of bounds). Para especificar el índice de
un elemento pueden emplearse tanto constantes como variables de tipo entero.
Otro error es tratar de emplear el identificador del array como si fuera un dato de tipo
primitivo. Por ejemplo, la sentencia
p = p + 34;
Se suelen emplear bucles cuando se quiere trabajar con todos los elementos de un array.
El siguiente ejemplo muestra como trabajar con todos los elementos de dos arrays de
números (uno de valores enteros y otro de valores reales). El segundo de ellos almacena la
raiz cuadrada de los valores almacenados en el primero:
/**?
* ArrayRaices: Ejemplo de uso de arrays
*/
public class ArrayRaices {?
public static void main (String [] args ) {
int [] numero = new int[10]; // Array de valores enteros
double [] raiz = new double[10]; // Array de valores reales
Es importante ver que el bucle for emplea la expresión i<numero.length como condición
de término.
Array de objetos
El uso de vectores no tiene por qué restringirse a elementos de tipo primitivo. Por
ejemplo, pueden crearse sendas referencias a arrays de referencias de la clase precio (tal y
como se declaró esta clase en un ejemplo anterior) o de la clase String:
precio [] catalogo; catalogo = new precio [5]; catalogo[0] = new
precio();
// Creacion de la referencia?// Creación del array de referencias?//
Creación del primer elemento/instancia precio
Arrays multidimensionales
En Java también se puede trabajar con arrays multidimensionales, llamados comúnmente
matrices. Por ejemplo, la declaración de un puntero a una matriz bidimensional de números
enteros se puede realizar de la siguiente manera incluyendo un par de corchetes adicionales en la
declaración de la referencia:
La creación de la matriz (una vez declarado su puntero) puede hacerse según muestra la
siguiente sentencia:
m = new int [5][4]; // Crea una matriz para almacenar 5 x 4 enteros
La ejecución del código anterior reserva espacio en memoria durante la ejecución del
programa para una matriz de 5 x 8 valores numéricos enteros. En realidad se reserva
espacio en memoria para un array de cinco punteros que, a su vez, almacenan la dirección
de memoria de otros tantos arrays de cuatro números enteros. Para referenciar a cada
uno de los elementos de los arrays de enteros es necesario utilizar el identificador del
puntero seguido de los correspondientes índices entre corchetes. Por ejemplo, como en
las siguientes sentencias:
m[0][0] = 34;
m[0][1] = 46;
m[0][2] = 13;
m[0][3] = -8;
m[1][0] = 5;
m[1][1] = 56;
m[1][2] = -3;
Por otro lado, también puede llevarse a cabo la declaración de la referencia, creación del
array multidimensional e inicialización simultánea de sus elementos. Por ejemplo, la
siguiente sentencia genera una matriz 2 x 3 de números enteros:
// Matriz de dos filas y tres columnas?
int [][] a = { {1, 2, 3}, {4, 5, 6} };?
// Por ejemplo, el elemento a[1][0] contiene el valor 4
Creación de un array bidimensional de 2 x 3 números enteros e inicialización de sus
elementos:
El número de elementos de los arrays referenciados puede especificarse para cada uno de
ellos y ser diferente entre sí. Por ejemplo, la ejecución de la sentencia:
int [][] b = { {1, 2, 3}, {4, 5, 6, 7}, {8, 9} };
En Java es posible trabajar con estructuras de tipo array con más de dos dimensiones
añadiendo simplemente los índices (y corchetes o llaves) que sean necesarios. Por
ejemplo, la siguiente sentencia crea una matriz tridimensional 2 x 2 x 3 de números
enteros:
int [][][] c = { { {1, 2, 3},{4, 5, 6} },{ {7, 8, 9}, {10, 11, 12} } }
6. Métodos en Java
Un método es un trozo de código que puede ser llamado o invocado por el programa
principal o por otro método para realizar alguna tarea específica. El término método en
Java es equivalente al de subprograma, rutina, subrutina, procedimiento o función en
otros lenguajes de programación. El método es llamado por su nombre o identificador
seguido por una secuencia de parámetros o argumentos (datos utilizados por el propio
método para sus cálculos) entre paréntesis. Cuando el método finaliza sus operaciones,
devuelve habitualmente un valor simple al programa que lo llama, que utiliza dicho valor
de la forma que le convenga. El tipo de dato devuelto por la sentencia return debe
coincidir con el tipo de dato declarado en la cabecera del método.
En el caso anterior, public y static son los modificadores especificados en la cabecera del
método. El uso de estos dos modificadores permite que el tipo de método sea similar al de
una función global de Pascal o C. El identificador double hace referencia al tipo de dato
que devuelve la llamada al método, cubo es el identificador del método y x es el
identificador del parámetro en la declaración de la cabecera del método (parámetro
formal). Ejemplo de ejecución del código anterior y salida correspondiente por pantalla:
$>java PruebaCubo
El cubo de 7.5 es: 421.875
En Java, los métodos suelen ir asociados con los objetos o instancias en particular a los
que operan (métodos de instancia). Los métodos que no necesitan o trabajan con objetos
(y sí con números, por ejemplo) se denominan métodos estáticos o de clase y se declaran
con el modificador static. Los métodos estáticos o de clase son equivalentes a las rutinas
(funciones o procedimientos) de los lenguajes que no emplean la programación orientada
a objetos. Por ejemplo, el método sqrt de la clase Math es un método estático. También lo
es el método cubo del ejemplo anterior. Por otro lado, todo programa o aplicación Java
tiene un método principal main que será siempre un método estático.
¿Por qué se emplea la palabra static para los métodos de clase? El significado o la
acepción más común de la palabra estático (que permanece quieto en un lugar) parece no
tener nada que ver con lo que hacen los métodos estáticos. Java emplea la palabra static
porque C++ lo utiliza en el mismo contexto: para designar métodos de clase.
Aprovechando su empleo en variables que tienen una única localización en memoria para
diferentes llamadas a métodos, C++ lo empezó a utilizar en la designación de los métodos
de clase para diferenciarlos de los métodos de instancia y no confundir al compilador. El
problema es que nadie pensó en que el uso de la palabra static pudiera causar
confusiones humanas.
Return y Void
En algunas ocasiones, no es necesario que el método estático tenga que devolver un valor
al finalizar su ejecución. En este caso, el tipo de dato que debe indicar en la cabecera de
declaración del método es el tipo void y la sentencia return no viene seguida de ninguna
expresión.
Sintaxis:
return;
En el siguiente código se incluye un ejemplo de método que no devuelve un valor (de tipo
void):
/**
* Demostracion del metodo tabla
Un método cuyo tipo de retorno no es void necesita siempre devolver algo. Si el código de
un método contiene varias sentencias if debe asegurarse de que cada una de las posibles
opciones devuelve un valor. En caso contrario, se generaría un error de compilación.
Por ejemplo:
/**
* Demostracion de la funcion esPositivo
*/
public class PruebaPositivo {
public static void main (String [] args) {
for (int i=5; i>=-5; i--)
System.out.println(i + " es positivo: " + esPositivo(i));
}
public static boolean esPositivo(int x) {
if (x<0) return false;
if (x>0) return true;
// Error: retorno perdido si x es igual a cero.
}
}
Recursión
/**
* Demostracion de la funcion recursiva factorial
*/
public class PruebaFactorialR {
public static void main (String [] args){
for (int i=1; i<=20; i++)
System.out.println("Factorial de " + i + " = " + factorialR(i));
}
}
public static long factorialR (int n) {
if (n==0)
return 1;
else
return n * factorialR(n-1);
}
}
En la construcción de métodos recursivos es importante evitar el problema de la recursión
infinita. Es decir, que en algún caso, la ejecución del método definido de forma recursiva
no implique una nueva llamada al propio método.
Java permite asignar el mismo identificador a distintos métodos, cuya diferencia reside en
el tipo o número de parámetros que utilicen. Esto resulta especialmente conveniente
cuando se desea llevar a cabo la misma tarea en difererente número o tipos de variables.
La sobrecarga (overloading) de los métodos puede resultar muy útil al efectuar llamadas a
un método, ya que en lugar de tener que recordar identificadores de métodos distintos,
basta con recordar uno sólo. El compilador se encarga de averiguar cuál de los métodos
que comparten identificador debe ejecutar. Por ejemplo:
/**
* Demostracion de metodos sobrecargados * A. Garcia-Beltran - marzo,
2002
*/
public class PruebaSobrecarga {
public static void main (String[] args) {
int a=34;
Tipos de métodos
Un método es una abstracción de una operación que puede hacer o realizarse con un
objeto. Una clase puede declarar cualquier número de métodos que lleven a cabo
operaciones de lo más variado con los objetos.
En esta sección los métodos se clasifican en dos grupos: los métodos de instancia y los
métodos de clase.
Métodos de instancia
Las clases pueden incluir en su declaración muchos métodos o no declarar ninguno. Los
métodos pueden clasificarse en métodos de instancia y métodos de clase.
Los métodos de instancia operan sobre las variables de instancia de los objetos pero
también tienen acceso a las variables de clase. La sintaxis de llamada a un método de
instancia es:
// Llamada tipica a un metodo de instancia
idReferencia.idMetodo(parametros);
Todas las instancias de una clase comparten la misma implementación para un método de
instancia. La instancia que hace la llamada al método es siempre un parámetro o
argumento implícito. Dentro de un método de instancia, el identificador de una variable
de instancia hace referencia al atributo de la instancia concreta que hace la llamada al
método (suponiendo que el identificador del atributo no ha sido ocultado por el de un
parámetro).
Métodos de clase
En principio, los métodos de clase no operan sobre las variables de instancia de los
objetos. Los métodos de clase pueden trabajar con las variables de clase pero no pueden
acceder a las variables de instancia declaradas dentro de la clase, a no ser que se crea una
nueva instancia y se acceda a las variables de instancia a través del nuevo objeto. Los
métodos de clase también pueden ser llamados precediéndolos con el identificador de la
clase, sin necesidad de utilizar el de una instancia.
Las diferencias entre los métodos de instancia y los de clase se resumen aquí:
7. Parámetros o argumentos
Los parámetros o argumentos son una forma de intercambiar información con el método.
Pueden servir para introducir datos para ejecutar el método (entrada) o para obtener o
modificar datos tras su ejecución (salida).
Declaración de parámetros
// Sin parametros
public double devuelve() {
return ...;
}
// Un parametro, x de tipo double
public void asigna(double x) {
...
}
// Dos parametros, a y b de tipo int
public int elMayor(int a, int b) {
...
}
// Un parametro, v, array real
public static double sumatorio (double [] v) {
...
}
// Un parámetro de la clase Fecha
public boolean caducado (Fecha fechaLimite) {
...
}
El identificador del parámetro se emplea sólo dentro del método para hacer referencia al
argumento correspondiente y puede coincidir con el de un atributo de la misma clase. En
tal caso, se dice que oculta a la variable miembro. Esta técnica suele emplearse en los
constructores para inicializar una instancia. Por ejemplo en la clase Circulo:
public class Circulo {
int x, y, radio;
La clase Circulo tiene tres atributos o variables miembro x, y y radio y un constructor con
tres argumentos con los mismos identificadores que facilitan los valores iniciales a los
atributos respectivamente. Los identificadores de los parámetros ocultan a las variables
miembro dentro del cuerpo del constructor, de forma que x, y y radio dentro del
constructor hacen referencia a los parámetros y no a las variables miembro. Para acceder
a las variables miembro, es necesario emplear la palabra reservada this que referencia a la
instancia que está siendo inicializada por el constructor.
public class Circulo {
int x, y, radio;
public Circulo(int x, int y, int radio) {
this.x = x; // this.x hace referencia al atributo x
// x hace referencia al parametro x
this.y = y; // this.y hace referencia al atributo y
// y hace referencia al parametro y
this.radio = radio;
}
}
Normalmente dentro del cuerpo del método de una clase puede hacerse referencia
directa a las variables miembro de las instancias. Salvo en el caso del ejemplo anterior en
el que las variables miembro están ocultas. Por otro lado, los parámetros de un mismo
método no puede compartir el mismo identificador (no pueden coincidir) con el de una
variable local. El siguiente código genera un error de compilación:
public void asigna(double x) {
// Un parametro, x de tipo double
double x; // Error de compilacion
...
}
/**
* Declaracion de la clase CuentaBancaria
* Ejemplo de declaracion de variables
* metodos estaticos y uso de this
*/
public class CuentaBancaria {
// Atributos o variables miembro
private double saldo;
public static int totalCuentas=0;
// Metodos
public CuentaBancaria() {
this(0.0);
CuentaBancaria c2;
c2 = new CuentaBancaria(20.0);
System.out.println("Nueva cuenta con: " + c2.saldo() + "
euros");
System.out.println("Total cuentas: " +
CuentaBancaria.totalCuentas);
System.out.println("Transferencia de cuenta 2 a cuenta 1");
c1.transferencia(c2);
System.out.println("Cuenta 1 con: " + c1.saldo() + " euros");
System.out.println("Cuenta 2 con: " + c2.saldo() + " euros");
}
}
La ejecución del código anterior origina la siguiente salida por pantalla:
saldo += origen.saldo;
origen.saldo=0;
}
En Java todos los parámetros de los métodos se pasan por valor. Cuando se realiza la
llamada a un método, los parámetros formales (parámetros indicados en la declaración)
reservan un espacio en memoria independiente y reciben los valores de los parámetros
reales (parámetros indicados en la llamada al método). ¿Qué consecuencias tiene el paso
por valor de los parámetros?
Cuando el argumento es de tipo primitivo, el paso por valor significa que durante la
ejecución del método se reserva un nuevo espacio para el parámetro formal y no se
puede modificar el parámetro real durante la ejecución del método.
Esto es a menudo una fuente de errores: el programador escribe un método que trata de
modificar el valor de uno de sus parámetros y el método no funciona como esperaba.
Variables locales
return x;
}
Una vez finalizada la ejecución del método, las variables locales k y x dejan de existir.
8. Constructores
Aunque en un principio pueda parecer lo contrario, un constructor no es en realidad un
método estrictamente hablando. Un constructor es un elemento de una clase cuyo
identificador coincide con el de la clase correspondiente y que tiene por objetivo obligar a
y controlar cómo se inicializa una instancia de una determinada clase, ya que el lenguaje
Java no permite que las variables miembro de una nueva instancia queden sin inicializar.
Además, a diferencia de los métodos, los constructores sólo se emplean cuando se quiere
crear una nueva instancia.
Por defecto toda clase tiene un constructor sin parámetros cuyo identificador coincide con
el de la clase y que, al ejecutarse, inicializa el valor de cada atributo de la nueva instancia:
los atributos de tipo primitivo se inicializan a 0 o false, mientras que los atributos de tipo
objeto (referencia) se inicializan a null.
Declaración de un constructor
9. Herencia
La herencia es una propiedad que permite la declaración de nuevas clases a partir de otras
ya existentes. Esto proporciona una de las ventajas principales de la Programación
Orientada a Objetos: la reutilización de código previamente desarrollado ya que permite a
una clase más específica incorporar la estructura y comportamiento de una clase más
general.
Cuando una clase B se construye a partir de otra A mediante la herencia, la clase B hereda
todos los atributos, métodos y clases internas de la clase A. Además la clase B puede
redefinir los componentes heredados y añadir atributos, métodos y clases internas
específicas.
Para indicar que la clase B (clase descendiente, derivada, hija o subclase) hereda de la
clase A (clase ascendiente, heredada, padre, base o superclase) se emplea la palabra
reservada extends en la cabecera de la declaración de la clase descendiente. La sintaxis es
la siguiente:
public class ClaseB extends ClaseA {?
// Declaracion de atributos y metodos especificos de ClaseB
// y/o redeclaracion de componentes heredados
}
// Metodos publicos
public double da() {
return this.euros;
}
Durante la ejecución del código anterior, se generan las instancias, referenciadas por p y
q, cada una de las cuales está compuesta por dos atributos: euros, variable de instancia
heredada de la clase Precio y codigo, variable de instancia específica de la clase Producto.
Jerarquía de clases
Java permite múltiples niveles de herencia pero no la herencia multiple, es decir una clase
sólo puede heredar directamente de una clase ascendiente. Por otro lado, una clase
puede ser ascendiente de tantas clases descendiente como se desee (un unico padre,
multitud de hijos). En la siguiente figura se muestra gráficamente un ejemplo de jerarquía
entre diferentes clases relacionadas mediante la herencia.
Se puede declarar un nuevo atributo con el mismo identificador que uno heredado,
quedando este atributo oculto. Esta técnica no es recomendable.
Se puede declarar un nuevo método de instancia con la misma cabecera que el de la clase
ascendiente, lo que supone su sobreescritura. Por lo tanto, la sobreescritura o redefinición
consiste en que métodos adicionales declarados en la clase descendiente con el mismo
nombre, tipo de dato devuelto y número y tipo de parámetros sustituyen a los heredados.
Se puede declarar un nuevo método de clase con la misma cabecera que el de la clase
ascendiente, lo que hace que éste quede oculto. Por lo tanto, los métodos de clase o
estáticos (declarados como static) no pueden ser redefinidos.
Un método declarado con el modificador final tampoco puede ser redefinido por una
clase derivada. Se puede declarar un constructor de la subclase que llame al de la
superclase de forma implícita o de mediante la palabra reservada super.
En general puede accederse a los métodos de la clase ascendiente que han sido
redefinidos empleando la palabra reservada super delante del identificador del método.
Este mecanismo sólo permite acceder al metodo perteneciente a la clase en el nivel
inmediatamente superior de la jerarquía de clases.
La clase object
Como consecuencia, todas las clases tienen algunos métodos heredados de la clase
Object.
Es bastante frecuente tener que sobreescribir algunos de estos métodos. Por ejemplo,
para verificar si dos instancias son iguales en el sentido de contener la misma información
en sus atributos se debería sobreescribir el método equals(). El siguiente código muestra
un ejemplo de módificación de la clase Producto para incluir una sobreescritura del
método equals():
Herencia y constructores
El casting o moldeo permite el uso de un objeto de una clase en lugar de otro de otras
clase con el que haya una relación de herencia. Por ejemplo:
Object a = new Producto();
Una clase abstracta es una clase de la que no se pueden crear instancias. Su utilidad
consiste en permitir que otras clases deriven de ella. De esta forma, proporciona un
modelo de referencia a seguir a la vez que una serie de métodos de utilidad general. Las
clases abstractas se declaran empleando la palabra reservada abstract como se muestra a
continuación:
public abstract class IdClase . . .
Una clase abstracta puede componerse de varios atributos y métodos pero debe tener, al
menos, un método abstracto (declarado también con la palabra reservada abstract en la
cabecera). Los métodos abstractos no se implementan en el código de la clase abstracta
pero las clases descendientes de ésta han de implementarlos o volver a declararlos como
abstractos (en cuyo caso la subclase también debe declararse como abstracta). En
cualquier caso, ha de indicarse el tipo de dato que devuelve y el número y tipo de
parámetros. La sintaxis de declaración de un método abstracto es:
abstract modificador tipo_retorno idClase(lista_parametros);
Si una clase tiene métodos abstractos, entonces también la clase debe declararse como
abstracta. Como los métodos de clase (static) no pueden ser redefinidos, un método
abstracto no puede ser estático. Tampoco tiene sentido que declarar constructores
abstractos ya que un constructor se emplea siempre al crear una instancia (y con las clases
abstractas no se crean instancias).
// Declaracion de metodos
abstract public double area();
public figuraGeometrica (String nombreFigura ) {
this.nombre = nombreFigura;
}
/**
* Ejemplo de uso de la clase Rectangulo
*/
public class pruebaRectangulo {
public static void main (String [] args ) {
Rectangulo r1;
r1 = new Rectangulo(12.5, 23.7);
System.out.println("Area de r1 = " + r1.area());
if (r1.mayorQue(r2))
System.out.println("El rectangulo de mayor area es r1");
else
System.out.println("El rectangulo de mayor area es r2");
}
}
Salida por pantalla de la ejecución del código anterior:
$>java PruebaRectangulo
Area de r1 = 296.25?
Area de r2 = Rectangulo con area 284.66
Una clase declarada con la palabra reservada final no puede tener clases descendientes.
Por ejemplo, la clase predefinida de Java Math está declarada como final.
A modo de ejemplo, se desarrolla una clase final MathBis (de operatividad similar a la
clase Math estándar de Java) que incluye la declaración de dos métodos que calculan y
devuelven respectivamente las siguientes funciones trigonométricas:
Mantener las clases con el principio de encapsulamiento nos permite controlar el cambio
de valor que pueda producirse en ellas añadiendo validaciones. De cualquier manera, es
una convención dentro de la programación orientada a objetos aunque no se esté
realizando una operación adicional al cambio de valor. Veamos un ejemplo:
public class Gato {
public String nombre;
public int patas;
}
//Mi método main...
Gato g = new Gato();
g.nombre = "Nemo";
g.patas = 4;
System.out.println("Mi gato se llama: " + g.nombre);
System.out.println("El número de patas de mi gato es: " + g.patas);
Por lo tanto, se nos ocurre, actualizar el método «setPatas» de nuestra clase Gato para
que quede así:
public void setPatas(int numeroPatas){
if(numeroPatas>=0 && numeroPatas<5){
patas = numeroPatas;
} else {
throw new IllegalArgumentException("Número de patas no
válido");
}
}
Con esta actualización del método, el segundo (tercer, cuarto, quinto..) equipo que use
nuestra clase gato, no va a variar su código (estabilidad) , seguirá llamando al método
setPatas (mantenibilidad), y nosotros controlaremos que el número sea entre 0 y 4
(seguridad). Si volvemos a la primera versión de la clase, no nos permitiría añadir este tipo
de controles a posteriori sin hacer cambiar todos los usos de nuestra clase.
Aunque parezca un ejemplo tonto (y un poco cruel para los gatos) no es raro en Java
encontrarte que tienes que trabajar con librerías que no conoces, que respetan el
principio de encapsulamiento y que gracias a él puedes hacer un correcto funcionamiento
de la misma, ya que controlará que no te salgas del tiesto, con valores inválidos, errores o
incluso validando los datos con los que se crea.
Ejemplo de Polimorfismo
Como todos los objetos Gato y Perro son objetos Animales, podemos hacer lo siguiente:
public static void main(String[ ] args) {
Animal a = new Dog();
Animal b = new Cat();
}
Creamos dos variables de referencia de tipo Animal y las apuntamos a los objetos Gato y
Perro. Ahora, podemos llamar a los métodos makeSound().
a.makeSound();
//salida "Woof"
b.makeSound();
//salida "Meow"
Como decía el polimorfismo, que se refiere a la idea de "tener muchas formas", ocurre
cuando hay una jerarquía de clases relacionadas entre sí a través de la herencia y este es
un buen ejemplo.
Polimorfismo paramétrico
Aquí el método demo() se sobrecarga 3 veces: el primer método tiene 1 parámetro int, el
segundo método tiene 2 parámetros int y el tercero tiene un parámetro doble. Por lo que
para lidiar con esta variedad el método que se llamará está determinado por los
argumentos que pasamos al llamar a los métodos. Esto sucede en tiempo de compilación
en tiempo de ejecución, por lo que este tipo de polimorfismo se conoce también como
polimorfismo en tiempo de compilación.
Salida de datos:
a: 10
a and b: 10,20
double a: 5.5
O/P : 30.25
Polimorfismo de inclusión
La habilidad para redefinir por completo el método de una superclase en una subclase es
lo que se conoce como polimorfismo de inclusión (o redefinición).
En él, una subclase define un método que existe en una superclase con una lista de
argumentos (si se define otra lista de argumentos, estaríamos haciendo sobrecarga y no
redefinición).
Un ejemplo muy básico en donde la clase Bishop sobreescribe el método move. Esto es el
polimorfismo de inclusión.
}
}
Diferencias entre polimorfismo y sobrecarga
El polimorfismo presenta unas claras ventajas aplicado desde las interfaces, ya que nos
permite crear nuevos tipos sin necesidad de modificar las clases ya existentes. Basta con
recompilar todo el código que incluye los nuevos tipos añadidos sin retocar la clase
anteriormente creada para añadir una nueva implementación lo que podría suponer una
revisión completa de todo el código donde se instancia la clase.
Por contra, un método está sobrecargado si dentro de una clase existen dos o más
declaraciones de dicho método con el mismo nombre pero con parámetros distintos, por
lo que no hay que confundirlo con polimorfismo.
El compilador, viendo los parámetros, sabe a qué método llamar en función del parámetro
que estás pasando. La sobrecarga se resuelve en tiempo de compilación utilizando los
nombres de los métodos y los tipos de sus parámetros; el polimorfismo se resuelve en
tiempo de ejecución del programa, esto es, mientras se ejecuta, en función de la clase a la
que pertenece el objeto.
Como ya se ha tratado en este artículo, en Java dos o más métodos dentro de la misma
clase pueden compartir el mismo nombre, siempre que sus declaraciones de parámetros
sean diferentes. Cuando esto sucede, se dice que estamos usando sobrecarga de métodos
(method overloading). En general sobrecargar un método consiste en declarar versiones
diferentes de él. Y aquí es donde el compilador se ocupa del resto y donde el término
Overloading significa que un mismo método tiene diferentes firmas mientras que
Overriding es el mismo método, por tanto misma firma, al que diferentes clases conectan
a través de la herencia. En algunos textos encontramos otra explicación en donde se
resume la sobrecarga como un ejemplo de polimorfismo en tiempo de compilación y la
sobreescritura como un ejemplo de polimorfismo en tiempo de ejecución.
Sí, es posible tener dos más métodos estáticos con el mismo nombre siempre que se
diferencien en los parámetros de entrada.
Sí, es posible siempre que definamos correctamente los parámetros de entrada como en
el siguiente ejemplo:
class Demo{
// Sobrecargando
public static void main(String arg1) {
System.out.println("Hello, " + arg1); // Hello Ducks
Demo.main("Dogs","Cats");
}
public static void main(String arg1, String arg2) {
System.out.println("Hello, " + arg1 + " and " + arg2); //
Hello Dogs and Cats
}
}
12. Interfaces
Una interfaz es una especie de plantilla para la construcción de clases. Normalmente una
interfaz se compone de un conjunto de declaraciones de cabeceras de métodos (sin
implementar, de forma similar a un método abstracto) que especifican un protocolo de
comportamiento para una o varias clases. Además, una clase puede implementar una o
varias interfaces: en ese caso, la clase debe proporcionar la declaración y definición de
todos los métodos de cada una de las interfaces o bien declararse como clase abstract.
Por otro lado, una interfaz puede emplearse también para declarar constantes que luego
puedan ser utilizadas por otras clases.
Una interfaz puede parecer similar a una clase abstracta, pero existen una serie de
diferencias entre una interfaz y una clase abstracta:
Todos los métodos de una interfaz se declaran implícitamente como abstractos y
públicos.
Una clase abstracta no puede implementar los métodos declarados como abstractos,
una interfaz no puede implementar ningún método (ya que todos son abstractos).
Una interfaz no declara variables de instancia.
Una clase puede implementar varias interfaces, pero sólo puede tener una clase
ascendiente directa.
Una clase abstracta pertenece a una jerarquía de clases mientras que una interfaz no
pertenece a una jerarquía de clases. En consecuencia, clases sin relación de herencia
pueden implementar la misma interfaz.
La declaración de una interfaz es similar a una clase, aunque emplea la palabra reservada
interface en lugar de class y no incluye ni la declaración de variables de instancia ni la
implementación del cuerpo de los métodos (sólo las cabeceras). La sintaxis de declaración
de una interfaz es la siguiente:
public interface IdentificadorInterfaz {
// Cuerpo de la interfaz ...
}
La interfaz declarada como public debe ser definida en un archivo con el mismo nombre
de la interfaz y con extensión .java. Las cabeceras de los métodos declarados en el cuerpo
de la interfaz se separan entre sí por caracteres de punto y coma y todos son declarados
implícitamente como public y abstract (se pueden omitir). Por su parte, todas las
constantes incluidas en una interfaz se declaran implícitamente como public, static y final
(también se pueden omitir) y es necesario inicializarlas en la misma sentencia de
declaración. La interfaz Modificacion declara la cabecera de un único método:
Segundo ejemplo: la interfaz constantes declara dos constantes reales con el siguiente
código fuente:
/**
* Declaracion de la interfaz Constantes
*/
public interface Constantes {
double VALOR_MAXIMO = 10000000.0;
double VALOR_MINIMO = -0.01;
}
Tercer ejemplo: la interfaz Numerico declara una constante real y dos cabeceras de
métodos con el siguiente código fuente:
/**
* Declaracion de la interfaz Numerico
*/
public interface Numerico {
double EPSILON = 0.000001;
void establecePrecision(float p);
void estableceMaximo(float m);
}
Para declarar una clase que implemente una interfaz es necesario utilizar la palabra
reservada implements en la cabecera de declaración de la clase. Las cabeceras de los
métodos (identificador y número y tipo de parámetros) deben aparecer en la clase tal y
como aparecen en la interfaz implementada. Por ejemplo, la clase Acumulador
implementa la interfaz Modificacion y por lo tanto debe declarar un método incremento:
03- Programación Orientada a Objetos Página 63
Lenguaje de Programación II Prof. Melvyn Quiñones
/**
* Declaracion de la clase Acumulador
*/
public class Acumulador implements Modificacion {
private int valor;
Otro ejemplo: pueden construirse dos interfaces, Constantes y Variaciones, y una clase,
Factura, que las implementa:
// Declaracion de la interfaz Constantes
public interface Constantes {
double valorMaximo = 10000000.0;
double valorMinimo = -0.01;
}
// Declaracion de la interfaz Variaciones
public interface Variaciones {
void asignaValor(double x);
void rebaja(double t);
}
// Declaracion de la clase Factura
public class Factura implements Constantes, Variaciones {
private double totalSinIVA;
public final static double IVA = 0.16;
Importante: Es peligroso modificar una interfaz ya que las clases dependientes dejan de
funcionar hasta que éstas implementen los nuevos métodos.
Una clase puede simultáneamente descender de otra clase e implementar una o varias
interfaces. En este caso la seccion implements se coloca a continuación de extends en la
cabecera de declaración de la clase. Por ejemplo:
public class ClaseDescendiente extends ClaseAscendiente implements
Interfaz {
...
}
Sólo una instancia de una clase que implemente la interfaz puede asignarse al parámetro
cuyo tipo corresponde al identificador de la interfaz. Esta facultad se puede aprovechar
dentro la propia interfaz. Por ejemplo:
public interface Comparable {?
// La instancia que llama a esMayor (this) y el parametro otra?
// deben ser de la misma clase o de clases que implementen esta
interfaz
// La funcion devuelve 1, 0, -1 si this es mayor, igual o menor
que otra
public int esMayor(Comparable otra);
}
En algún caso puede ser útil declarar una interfaz vacía como, por ejemplo:
public interface Marcador { }
Cada paquete en Java tiene su nombre único y organiza sus clases e interfaces en un
espacio de nombres o grupo de nombres separados.
Aunque las interfaces y las clases con el mismo nombre no pueden aparecer en el mismo
paquete, pueden aparecer en diferentes paquetes. Esto es posible asignando un espacio
de nombre separado a cada paquete.
Sintaxis:
paquete nameOfPackage;
Definimos una clase y un objeto y luego lo compilamos en nuestro paquete p1. Después
de la compilación, ejecutamos el código como un paquete java:
Donde:
1) Para poner una clase en un paquete, en la primera línea de código define el paquete
p1
2) Crea una clase c1
3) Definiendo un método m1 que imprime una línea.
4) Definiendo el método principal
5) Creando un objeto de clase c1
6) Método de llamada m1
La compilación está completa. Se crea un archivo de clase c1. Sin embargo, no se crea
ningún paquete. El siguiente paso tiene la solución.
Paso 5. Cuando ejecuta el código, crea un paquete p1. Cuando abras el paquete java p1
dentro, verás el archivo c1.class.
Paso 7. Ahora digamos que desea crear un paquete secundario p2 dentro de nuestro
paquete java existente p1. Entonces modificaremos nuestro código como:
paquete p1.p2
Así es como se ejecuta el paquete y da el resultado como “m1 de c1” desde el archivo de
código.
Importar paquetes
Para crear un objeto de una clase (incluido en un paquete), en su código, debe usar su
nombre completo.
Ejemplo:
java.awt.event.actionListner object= new java.awt.event.actionListner ();
Sin embargo, podría ser tedioso escribir el nombre de ruta del paquete separado por
puntos para cada clase que desee utilizar. En cambio, se recomienda que use la
declaración de importación.
Sintaxis:
import packageName;
Una vez importado, puede usar la clase sin mencionar su nombre completamente
calificado.
import java.awt.event. *;
// * significa que todas las clases en este paquete son importadas
import javax.swing.JFrame // aquí solo se importa la clase JFrame
//Uso
JFrame f = nuevo JFrame; // sin nombre completamente calificado.
Paso 2. Guarde el archivo como Demo2.java. Compila el archivo usando el comando javac
-d. Demo2.java
Para evitar nombrar conflictos, los paquetes reciben los nombres del nombre de dominio
de la compañía en Ex inverso: com.guru99. com.microsoft, com.infosys etc.
Al crear un paquete, se debe tener cuidado de que la declaración para crear el paquete se
debe escribir antes que cualquier otra declaración de importación:
// No permitido
import el paquete p1. *;
paquete p3;
// sintaxis correcta
paquete p3;
import el paquete p1. *;
El paquete java.lang se importa de forma predeterminada para cualquier clase que cree
en Java.
La API de Java es muy extensa, contiene clases que pueden realizar casi todas sus tareas
de programación desde la manipulación de la estructura de datos hasta la creación de
redes. La mayoría de las veces, usará archivos API en su código.
Protección de acceso
Dada la interacción entre clases y paquetes, Java establece cuatro categorías de visibilidad
para los miembros de clase:
Subclases del mismo paquete
No subclases del mismo paquete
Subclases de diferentes paquetes
Clases que no están en el mismo paquete ni a las subclases
Los especificadores de acceso: private, public, protected proporcionan una gran variedad
de formas para producir los diferentes niveles de acceso que necesitan. La siguiente tabla
resume las interacciones:
Los miembros explícitamente declarados públicos (public) son los más visibles, y se puede
acceder desde diferentes clases y diferentes paquetes.
Un miembro privado (private) es accesible solo para los otros miembros de su clase. Un
miembro privado no se ve afectado por su membresía en un paquete.
Una clase de nivel superior tiene solo dos niveles de acceso posibles: predeterminado y
público. Cuando una clase se declara como pública, se puede acceder fuera de su paquete.
Si una clase tiene acceso predeterminado, solo se puede acceder por otro código dentro
de su mismo paquete. Además, una clase que se declara pública debe residir en un archivo
con el mismo nombre.
¿Cómo sabe el intérprete de Java donde debe buscar los paquetes que se van creando? En
primer lugar la interpreta utiliza por defecto el directorio de trabajo como punto de
partida, por lo tanto lo encontrará si el paquete está en este directorio o en un
subdirectorio. En segundo lugar, se puede especificar una ruta de directorio, ajustando la
variable de entorno CLASSPATH.
EJERCICIOS DE EVALUACIÓN
Contesta.
1. ¿Qué es la Programación Orientada a Objetos (POO)?
2. ¿Cuál fue el primer lenguaje de programación que utilizó POO y quiénes lo crearon?
3. ¿En qué difiere la POO de la programación estructurada?
4. Defina los siguientes conceptos:
Evento
Atributos
Mensaje
Propiedad o atributo
Estado interno
Miembros de un objeto
Identificación de un objeto
variable
firma
5. Defina las características de la POO.
6. ¿Cuál es la corriente de POO que utiliza el lenguaje Java y por qué?
7. ¿Qué es un objeto?
8. ¿Qué es un campo o atributo?
9. ¿Qué es una rutina o método?
10. ¿Qué es una clase?
11. ¿Cómo deben nombrarse los identificadores de las clases?
12. ¿Qué es una instancia?
13. Elabore una porción de código que describa la instanciación de una clase.
14. ¿Qué es una referencia o puntero?
15. ¿Para qué sirve el operador instanceof?
16. Defina los modificadores de visibiliad o acceso.
17. Mencione 10 lenguajes que utilizan POO.
18. ¿Qué son variables de instancia?
19. ¿Qué son variables de clase?
20. ¿Para qué sirve la palabra reservada "final"?
21. Elabore una porción de código que describa el uso de variables de tipo final.
22. ¿Qué son los wrappers?
23. Mencione las clases contenedoras o wrappers de los tipos de datos primitivos en java.
24. Defina los métodos que componen la clase Character.
REFERENCIAS
https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos
https://www.arkaitzgarro.com/java
https://javadesdecero.es/poo/modificadores-de-acceso/
https://juanjavierrg.com/java-basico-encapsulamiento/
https://guru99.es/java-packages/#top
https://javadesdecero.es/intermedio/paquetes-en-java/
https://www.pcresumen.com/menu-software/35-lenguajes-de-programacion/java/72-los-
paquetes-en-java
https://www.tutorialesprogramacionya.com/javaya/