Java desde Cero – Sobrecarga de Constructores – Clases y Métodos

Recordemos que un constructor otorga un estado inicial a las propiedades de la clase; sin embargo, existirá ocasiones en que una misma instancia de clase deseemos que se inicie de distintas formas, hacer que una clase pueda inicializarse de distintas formas se logra a través de la sobrecarga de constructores, la sobrecarga de constructores sea método o de clase es la creación de varios constructores  o métodos con el mismo nombre pero con diferente lista de tipos de parámetros o número de ellos, si no lo haces el compilador de Java no sabría a que constructor estás haciendo referencia y lanzaría un error.

¿Cuántos constructores por clase podemos crear?, pues siempre que se cumpla la condición mencionada, podría ser incluso infinito. Revisemos un ejemplo de gatitos:

package clases;
/**
 * Gatos
 */

public class Gatos {
    public static void main(String[] args) {
        Gatos gatito1=new Gatos();
        Gatos gatito2=new Gatos("Asrael", 10);
        System.out.println("Gatito 1 se llama: " + gatito1.nombre);
        System.out.println("Gatito 2 su edad es: "+  gatito2.nombre);
        gatito1.cambiar();
        gatito2.cambiar("Cielo");
        System.out.println("Gatito 1 se llama: " + gatito1.nombre);
        System.out.println("Gatito 2 su edad es: "+  gatito2.nombre);

    }

    String nombre;
    int edad;
    public Gatos(){
        this.nombre="Michifus";
        this.edad=7;
    }

    public Gatos(String nombre, int edad){
        this.nombre=nombre;
        this.edad=edad;
    }

    String cambiar(){
        this.nombre="Juanelo";
        return this.nombre;
    }

    String cambiar(String nuevo_nombre){
        this.nombre=nuevo_nombre;
        return this.nombre;
    }
}

Analicemos el ejemplo en cuestión, hemos creado una clase llamada Gatos, la clase tiene propiedades como el nombre y la edad, luego de ello creamos el primer constructor, el primer constructor no requiere de parámetros, asigna arbitrariamente valores de inicio a las propiedades descritas; el segundo constructor como observamos sí recibe parámetros, en este caso del nombre y la edad; luego de ello de similar forma al constructor creamos dos métodos que modificarán el nombre de nuestras instancias, observemos que retornan el valor que modifican, no hemos colocado en modo private a las propiedades es por ello que podemos acceder a ella. Finalmente en el método main hemos creado instancias de la clase haciendo uso de los 2 constructores y luego llamando a los mismos métodos, en ambos casos imprimiendo los resultados antes de ejecutar un cambio y posterior a ello. Demos algunos detalles más sobre este asunto, imaginemos que tenemos el siguiente método:

public void unNumero(int numero){ //código}
public void unNumero(float numero){//código}

La diferencia entre ellos es el tipo de argumento que reciben, tenlo mucho en cuenta. Otro asunto que debes considerar es que el tipo de retorno NO sirve para distinguir métodos. Si dos métodos tienen el mismo número de argumentos con tipos iguales nos lazará un error en tiempo de compilación:

public int unNumero(int numero){ //código}
public float unNumero(float numero){//código}

Ahora ¿Qué ocurre si creamos un constructor de la siguiente forma?:

  public Gatos(String nombre){
        this.nombre=nombre;
    } 

Tenemos un constructor que solo debemos de ingresar el nombre y que si intentamos hacer:

 System.out.println("Gatito 3 su edad es: "+  gatito3.nombre+ " y la edad es: "+gatito3.edad); 

Observaremos que la edad nos arroja un valor igual a cero, y esto porque no hemos asignado un valor inicial a la edad en este constructor, ¿Qué ocurre que si de igual forma queremos que tome un valor por defecto?, primera solución revisada fue inicializar por defecto, pero la segunda es hacer uso del this:

 public Gatos(String nombre){
        this(nombre,7);
    } 

¿Qué estamos haciendo?, pues estamos llamando a un constructor hecho ya de la clase, aquí quizá no se aprecie mucho dado que solo tenemos 3 constructores, pero ¿Qué constructor es el que se ha de llamar?, pues del que coincida tanto en el tipo como cantidad de parámetros que incluyamos en el this.

Java desde Cero – Constantes – uso de Final y Static

INTRODUCCIÓN

En anteriores oportunidades hemos entendido el que una variable se declara por el tipo de dato sea primitivo o de referencia y su respectiva inicialización, esto surge a la inexorable necesidad de todo lenguaje de programación de almacenar y manipular información, para ello estos datos se almacenan temporalmente en la memoria del ordenador, las variables no son más que “nombres” que “apuntan” a una determinada parte de la memoria y que es usada para leer y escribir de forma controlada. El acceso a esta información se puede mejorar dependiendo del tipo de información que almacenemos. Por ejemplo, no es lo mismo tener la necesidad de manejar números, que letras o conjuntos de datos; aunque al final todo son ceros y unos dentro de la memoria, es la forma de interpretarlos lo que marca la diferencia, tanto al almacenarlos como al recuperarlos.

Ahora bien, tan igual que existen las variables, también existen las constantes en Java, podemos definir una constante como un valor propio de la clase que es inmutable; por ejemplo si tratásemos con el número PI. PI es una constante matemática empleada para diversos tipos de operaciones, las más resaltantes en el uso geométrico para la determinación del área y longitud de una circunferencia por ejemplo; entonces, vamos a crear dos métodos que nos permitan determinar el área y la longitud de una circunferencia

class Circunferencia{
  private double PI;
  public Circunferencia(){
      PI=3.14;
  }

  public double area(doubleradio){
      double area=PI*Math.pow(radio,2);
      return area;
  }

  public double longitud(doubleradio){
      double longitud=PI*2*radio;
      return longitud;
  }

  /**
  * @return the pI
  */

  public double getPI(){
      return PI;
  }

}

Si observamos no tiene nada de particular, PI es una variable que puede ser accesada a través de su getter, esto no es una constante, solo una variable que ha sido ya inicializada ¿verdad?, ¿Qué ocurre además?, como hemos mencionado el hecho que sea una variable hace que cuando se instancie un objeto de la clase se cree un espacio en memoria para la variable PI tantas veces como objetos de la clase podamos crear, lo cual al ser una constante resulta realmente ineficiente

¿CÓMO SE DECLARA UNA CONSTANTE?

En java declarar una constante requiere del uso de la palabra reservada “final”, podemos hacer entonces:

private final double PI=3.14;

En este contexto indica que una variable es de tipo constante, no admitirá cambios luego de su declaración y asignación de valor; final determina que un atributo no puede ser sobreescrito o redefinido. Toda constante declarada con “final” ha de ser inicializada en la misma linea que es declarada; solo por aclaración “final” también puede ser usada en otro contexto para indicar que una clase no puede tener clases que la hereden. Una de las practicas comunes al declarar una constante es usar letras mayúsculas y en la cabecera de la clase antes del constructor de la clase.

USO DE STATIC EN CONSTANTES

Revisemos algo, cuando queremos crear una constante estamos decidiendo que dicho valor será usado por todos los objetos de la clase y será inmutable, ¿Qué sucede si solo usamos final?, es cierto que hemos creado una constante, pero en cada instancia, se creará una constante por cada objeto que se vaya a crear volviendo nuevamente a una asignación de espacio en memoria por instancia, lo cual, nuevamente no tiene mucho sentido, nosotros debemos asegurar que sea inmutable y que sea una única asignación que sea compartida por todos los objetos de la clase, aquí debemos de enfatizar en algo, los atributos miembros de una clase pueden ser atributos de clase o atributos de instancia; se dice que son atributos de clase si se usa la palabra reservada “static“, en ese caso la variable única para todas las instancias de la clase ocupa un único lugar en memoria, entonces:

public static final double PI=3.14;

Hemos cambiado su modificador de acceso, ya que toda constante, variable o método que se le asigne “static” ahora podrá ser llamado directamente haciendo uso de la clase:

System.out.println(Circunferencia.PI);

USO DE STATIC EN MÉTODOS

Tal como hemos mencionado la palabra reservada static también es aplicable a un método, la particularidad de asignar static a un método:

  • Hace que el método solo pueda acceder a datos static.
  • Un método static puede llamar solo a otros métodos static.
  • Un método static se puede acceder directamente por el nombre de la clase y no se necesita crear un objeto para acceder al método (aunque si es posible como en las variables).
  • Un método static no puede hacer referencia a “this” o “super“.

Nuestro método de longitud lo convertimos a estático:

public static double longitud(double radio){
  double longitud=PI*2*radio;
  return longitud;

}

Ahora podemos invocarlos directamente con la clase sin necesidad de instanciar un objeto.

System.out.println(Circunferencia.longitud((5)));

Aquí observamos el uso de static en métodos.

Java desde Cero – POO – Construcción de Objetos

INTRODUCCIÓN

Anteriormente ya hemos tocado con relativa ligereza todo lo relacionado al paradigma de la programación orientada a objetos (POO), finalmente observamos los getters y setters como una buena práctica para acceder y configurar variables que consideremos que no deban estar expuestas directamente al usuario, es cierto que se puede crear un método que pueda comportarse como setter y getter pero ello no es recomendado como una buena práctica.

CASO

Vamos a realizar un caso práctico para observar el uso de la construcción de objetos, vamos a crear una clase “Alumno“, el cual tiene como característica que tiene un nombre, paga una pensión, tiene una fecha de ingreso y le crearemos un método que sea subir pensión, entonces manos a la obra, para crear una clase recordemos que debemos de usar la palabra reservada class y además de ello hemos de crear un constructor, la caracaterística principal del constructor es que sea public y que tenga el mismo nombre que el de la clase, este constructor ha de recibir parámetros, los parámetros son nombre, pensión, año de ingreso, mes de ingreso y día de ingreso, estos parámetros serán de tipo String, double int, int, e int respectivamente. Estos parámetros tendrán sus correspondientes propiedades de la clase, es decir existirá una propiedad nombre que ha de recibir el parámetro nombre, debemos de distinguir la propiedad del parámetro a través del uso de la palabra reservada this, aunque el único diferente será lo referido al ingreso, para ello haremos uso de la clase  LocalDate que nos permite configurar una fecha a través de uno de sus métodos (of que es de tipo estático el cual trataremos más adelante) entonces:

package clases.Alumnos;

import java.time.LocalDate;

/**
* Alumno
*/

public class Alumno {

 private String nombre;
 private LocalDate ingreso;
 private double pension;

 public Alumno(String nombre,double pension,int anio,int mes,int dia){

   this.nombre=nombre;
   this.pension=pension;
   this.ingreso=LocalDate.of(anio, mes, dia);

 }

}

Nota que hemos importado el paquete java.time el cual es parte de las implementaciones del JDK 1.8 (aquí encontrarás más sobre  of) Hemos declarado las propiedades y en el constructor las hemos definido a través de los parámetros.  Ahora debemos de crear los métodos setters y getters que nos permitan configurar y acceder a las propiedades de tipo private, ¿Pero de que propiedades necesitamos?, en líneas generales debes acceder a todas las propiedades; sin embargo, solo necesitamos poder setear la que corresponde a la pensión, es entonces que solo a pensión se le crea un método setter:

public String getNombre(){
  return nombre;
}

public LocalDate getIngreso(){
  return ingreso;
}

public double getPension(){
  return pension;
}

public void setPension(double porcentaje){
  this.pension= this.pension*(1+(porcentaje/100));
}

Note la siguiente particularidad, en setPension(), recibimos como parámetro un porcentaje con el cual se realiza el cálculo de la nueva pensión en función de ese porcentaje y se agrega a la pensión.  Hemos terminado de configurar nuestra clase Alumno, ahora podemos crear una clase cualquiera (Principal en mi caso) donde contenga el método main, e instanciamos  un objeto de la clase Alumno:

package clases.Alumnos;

/**
* Principal
*/

public class Principal {

  public static void main(String[] args){

     Alumno alumno1=new Alumno("Henry Medina",750,2016,02,12);
  }

}

Sin embargo, hacerlo de esta forma sería muy tediosa si en caso tuviéramos muchos alumnos, podemos hacerlo quizá a través del uso de los “Arrays” , entonces vamos a crear una array de nombres, pensiones, y fechas:

publicstaticvoidmain(String[]args){

  String[] nombres={"Henry Medina","Emily Fernandez","Cecilia Panebra"};
  double[] pensiones={750,850,1200};
  String[] fechas={"2016/02/12","2015/12/01","2017/03/15"};
  Alumno[] alumnos=new Alumno[3];

  for(int i =0; i < nombres.length; i++){
    String[] partes=fechas[i].split("/");
    alumnos[i]=new Alumno(nombres[i], pensiones[i], Integer.parseInt(partes[0]), Integer.parseInt(partes[1]), Integer.parseInt(partes[2]));
 }

  for(Alumno alumno : alumnos){
   System.out.println(alumno.getNombre()+" tiene una pensión de: "+alumno.getPension()+" e ingreso en fecha: "+alumno.getIngreso());

 }

}

Los arrays de los nombres y pensiones no tienen complicación, nótese que las fechas son introducidas como si de un string se tratase, hemos creado el arreglo de alumnos que está conformado por instancias de la clase Alumno; sin embargo, aún no los hemos inicializado, para ello vamos hacer uso del bucle for, ¿Qué es lo primero que hacemos en el bucle?, recuerdese que el constructor de Alumno, pide el año, mes y el día como enteros y nosotros solo estamos recibiendo un string; entonces, el primer paso consiste en obtener de cada fecha su año, mes y su día y lo almacenamos en un arreglo que hemos llamado partes, para lograr ello usamos el método split el cual requiere como parámetro que se indique el caracter separador (“/”), entonces tendremos que partes será para la primera fecha será:

partes={"2016","02","12"}

Hecho esto llamamos a la posición i del arreglo alumno (i va desde el 0 hasta el 2) he inicializamos las instancias, asignando de igual forma el nombre y pensión en la posición i, cuando tenemos que introducir la fecha tenemos que asignar las posiciones del arreglo partes; sin embargo, estos son strings, para ello debemos parsear o castear desde un tipo string a un tipo int, esto lo logramos con el método estático parseInt(String x) que pertenece a la clase Integer y que recibe como parámetro un String, es por ello que cada elemento es parseado y entregado al constructor:

Integer.parseInt(partes[0])

Hecho esto, procedemos luego a imprimir cada uno de los resultados, para ello usamos el bucle for each, ¿Qué de particular notamos?, pues que estamos accediendo a las propiedades no directamente (ya que están encapsuladas) sino a través de su respectivo método getter. Ahora vamos hacer uso del método setPension(), lo podríamos hacer agregando al bucle foreach el método, es decir:

for(Alumno alumno : alumnos){
    alumno.setPension(5);
    System.out.println(alumno.getNombre()+" tiene una pensión de: "+alumno.getPension()+" e ingreso en fecha: "+alumno.getIngreso());
}

Verás que los valores impresos han sido aumentados en un 5%, este ha sido un ejemplo en el cual hemos usado casi todo lo que hemos aprendido hasta el momento, saludos.

Java desde Cero – Programación Orientada a Objetos 2

INTRODUCCIÓN

Anteriormente ya hemos revisado el paradigma de la programación orientada a objetos (POO), que en resumen es el modelado del programa como si fueran objetos de la vida real;  también observamos que el agrupamiento de las características comunes en los objetos se hace a través de las clases, así también explicamos el concepto de modularización como parte de una buena práctica para concentrar segmentos de código que nos permitan un funcionamiento limpio y sencillo para el tratamiento de errores; finalmente observamos el encapsulamiento que es la restricción de ciertas propiedades que no deben ser visibles al usuario, razones miles por las cuáles no deseamos que lo sean, pero ¿Cómo podemos acceder a ellas?, en este post haremos un tratamiento al respecto.

La programación orientada a objetos, no nos debe permitir modificar las propiedades de una clase a no ser que sea a través del canal correspondiente, el canal correspondiente se realiza a través de los métodos, específicamente a través de los métodos getter o setter, antes de ello debemos definir que es un método.

MÉTODOS

Por el principio de modularidad un problema complejo debe ser subdividido en subproblemas (problemas más sencillos) y así sucesivamente hasta que los problemas más pequeños sean sencillos de resolver, esto es conocido como diseño descendente (top-down design) y se denomina descendente porque empieza en la parte superior.

metodo

Los subalgoritmos pueden entenderse como subprogramas para resolver un aspecto específico del gran problema, a este tipo de subprogramas se le denomina método o función. Matemáticamente una función, es una operación que toma uno o más valores llamados argumentos y produce un valor denominada resultado, Java como hemos observado tiene funciones (métodos) predeterminados:

Math.pow()
Math.sqrt()
System.out.println()

Sin embargo, el usuario también puede definir sus propias funciones, por ejemplo:

metodo2

 Donde f es el nombre de la función y x es el argumento. Obsérvese que ningún valor específico se asocia con x, es un parámetro formal utilizado en la definición de la función.  Para evaluar f debemos de darle un valor real a x, por ejemplo si x=3 f será 0.3. En java un método sigue la siguiente sintaxis:

[Modificador_de_acceso] tipo_de_dato Nombre ([parámetros])[throws lista_excepciones]{
          sentencias
          [return resultado]
}
  • Modificador de acceso [opcional]: Determinan el tipo de acceso al método (private, public, etc).
  • Tipo de dato: Indica el tipo del valor que devuelve el método. En java es imprescindible que en la declaración de un método se indique el tipo de dato que ha de devolver. El dato se devuelve mediante la instrucción return. Si el método no devuelve ningún valor este tipo será void.
  • Nombre: Es el nombre que se le da al método. Para crearlo hay que seguir las mismas normas que para crear nombres de variables.
  • Parámetros [opcional]: Después del nombre del método y siempre entre paréntesis puede aparecer una lista de parámetros (también conocidos como argumentos) separados por comas. Estos parámetros son los datos de entrada que recibe el método para operar con ellos, un método puede recibir cero o más argumentos, por cada parámetro que se introduzca se debe indicar su tipo como si declarásemos una variable.
  • Throws lista de Excepciones [opcional]: Indica las excepciones que puede generar y manipular el método, este desarrollo lo veremos más adelante.
  • return [opcional]: Se utiliza para devolver un valor. La palabra return va seguida de una expresión que será evaluada para saber el valor del retorno. Esta expresión puede ser compleja o puede ser simplemente el nombre de un objeto, una variable de tipo primitivo o una constante. El tipo de valor de retorno debe coincidir con el tipo de dato declarado en el método. Si el método no devuelve nada entonces el tipo de dato será void y la instrucción return se volverá opcional. El inicio y fin de un método se da entre las llaves { }.

Aquí algunos ejemplos:

private void correr(int velocidad){
  System.out.println("Hola la velocidad es: " + velocidad);

}

public double calculo_velocidad(int distancia,int tiempo){
  double velocidad=distancia/tiempo;
  return velocidad;
}

SETTERS Y GETTERS

Tal como hemos mencionado encapsular un atributo o método significa restringir su uso a otras instancias de la clase y que solo pueden ser modificadas dentro de la clase misma donde fueron creadas, se estila su uso para proteger características propias del constructor de la clase o de métodos que no deben ser alterados porque son de uso común; sin embargo, si bien es cierto que se deben proteger también deben de existir mecanismos que nos permitan tener acceso a dichos atributos, y en el encapsulamiento los métodos adecuados son los métodos  setter y getter. Un método setter define el valor de la propiedad y un getter obtiene el valor de una propiedad, existen convenciones sobre su implementación:

Método Getter:

public tipo get+nombre_variable(){
   return variable
}

public double getAlto() {
   return alto;
}

Como puede observarse el método getter inicia con un modificador de acceso public, esto es pues debe ser accesible desde otras clases, no tendría sentido si no lo fuera, luego debe indicar el tipo que ha de devolver (eso ya se ha explicado líneas arriba), definido el tipo debe colocar  la palabra get como un prefijo más el nombre de la variable que hace referencia, lo demás sigue la misma estructura de un método, get es una convención que permite a otros programadores que observen tu código entender que haces referencia a un método getter.

Método Setter:

public void set+nombre_variable(parámetro){
   this.nombre_variable=parámetro
}

public void setAlto(double alto) {
  this.alto= alto;
}

Nuevamente el modificador de acceso es public ya que estará accesible desde otras clases, usar el tipo void, lo que como ya hemos definido significa que no devuelve valor alguno y el return no se coloca; sin embargo, lo nuevo es que ahora el método recibe un parámetro, el parámetro debe ser del mismo tipo de la propiedad que ha de modificar; otro aspecto es el uso de la palabra reservada this. Aunque su aplicación es mayor, this, nos permite realizar una referencia al objeto asociado, por ejemplo si el parámetro recibido le hemos asignado el nombre de “alto” y tenemos una propiedad “alto“, hacer this.alto indica que se está haciendo referencia a una propiedad del objeto y no al parámetro, si colocáramos simplemente alto java entendería que solo estamos haciendo referencia al parámetro.

 

Java desde Cero – Programación Orientada a Objetos 1

INTRODUCCIÓN

Java es un lenguaje de programación orientado a objetos (POP), POO es un paradigma de la programación actualmente vigente, básicamente consiste en dar a los elementos que componen un programa el comportamiento y propiedades que tienen los objetos en la vida real y dado que ya estamos familiarizados con el trato de los objetos del mundo real en el día a día, establecer una relación hacia la programación de software debía ser más sencillo o comprensible. No se trata de nuevas características sino de una NUEVA FORMA DE PENSAR viendo a la programación y su composición como observamos a los objetos en la vida real.

¿QUÉ OBSERVAMOS EN LOS OBJETOS?

Los objetos tienen un estado, un comportamiento ( también conocido como capacidades, cosas que pueden hacer) y propiedades. Por ejemplo pensemos en un Televisor (no importa la marca):

televisor-samsung-43-smart-tv-full-hd-serie-5-un43j5200dkxzl.jpg

¿Qué estado puede tener?

  • Prendido o apagado, quizá en algunos, suspendido

¿Qué propiedades podemos observar?:

  • Tiene un ancho, alto y grosor, color, parlantes, soporte, etc.

¿Qué comportamientos o capacidades?, ¿Qué cosas puede hacer?

  • Prender, apagar, manipular el volumen de sonido, etc.

¿CÓMO BENEFICIA O EXPRESA EN LA PROGRAMACIÓN ESTE PARADIGMA ORIENTADO A OBJETOS?

El programa puede  dividirse en partes (modularización)   y agruparse en función de clases que permitan su identificación y reutilización (Herencia), algunas de esas agrupaciones no están expuestas al usuario a simple vista (encapsulamiento) (como los circuitos del televisor para que no se haga daño el usuario);  de forma más sencilla, tiene entre otras ventajas que el mal funcionamiento de un módulo (por el momento un segmento del código) no implica la caída total del programa, tan igual que sucede en la vida real, si una parte de la pantalla se estropea no implica que todo el televisor deje de funcionar (obviamente se verá mal, pero el funcionamiento proseguirá), y así también nos permite hacer el tratamiento del mismo, ocurre de forma similar en el software a través del manejo de las Excepciones.

CLASES

¿Qué es una clase?, podemos decir que una clase es una plantilla o modelo que definen las características y métodos (funciones que están dentro de una clase)  comunes a un grupo de objetos. Cuando se define una clase, se declara su forma y naturaleza de forma exacta; para hacerlo más comprensible vamos a tratar objetos de la vida real, pensemos en bicicletas:

mens-roadster-negro-1

Pensar en una bicicleta  y sus componentes en términos generales es saber que tiene: 2 ruedas, frenos, cadena, silla, tubos, pedal, timón, etc (no uso bicicletas). Podemos decir que estos componentes son las características comunes a todas las bicicletas; sin embargo, incluso las bicicletas a través de estas características comunes poseen una medida de estas características, como por ejemplo el color de los tubos, las dimensiones de las ruedas, el material que las compone, etc. También tienen una serie de comportamientos (cosas que pueden hacer que también conocidos como métodos):

2022185043700_2

 

plegable-fabric

Si las clases son los modelos de las características y métodos que poseen en común un conjunto de objetos, podemos decir entonces que un objeto es la representación o instancia de una clase.

Llevemos todo esto a código:

En Java una clase se expresa a través de la palabra reservada Class, se estila que el nombre de la clase inicie con mayúsculas y que tenga el mismo nombre que tiene el archivo, entonces si creamos un archivo Bicicleta.java debemos de crear nuestra primera clase como:

public class Bicicleta {
 int ruedas;
 int asientos;
 double largo;
 double alto;
 String color;
 String material;
 int peso;
}

Nota que tenemos  otra palabra reservada denominada public, por el momento no le tomes atención pero te adelanto que pertenece a los modificadores de acceso; entonces dentro de la clase hemos definido las propiedades de la clase bicicleta, pero aún no le hemos dado un estado inicial (inicializado), para inicializar estas propiedades debemos de hacer uso de otro componente de la clase que se denomina el constructor. El constructor es un método especial de una clase que se llama automáticamente siempre que se declara una instancia (objeto) de la clase, ya que cuando se crea un objeto en Java se realizan las siguientes operaciones:

  • Se asigna memoria para el objeto.
  • Se inicializan los atributos de ese objeto con los valores predeterminados del sistema.
  • Se llama al constructor de la clase que pueden ser uno o varios.

¿Cómo se reconoce a un constructor?, pues debe llevar el mismo nombre de la clase y el uso de la palabra reservada public. Veamos como se expresa en código:

class Bicicleta {
    int ruedas;
    int asientos;
    double largo;
    double alto;
    String color;
    String material;
    int peso;

  public Bicicleta(){

      ruedas=2;
      asientos=1;
      largo=1.5;
      alto=0.5;
      color="Amarillo";
      material="Azul";
      peso=20;

  }

}

Ahora, ¿Cómo hacemos uso de las clases?, pues a través de sus instancias, entonces debemos de instanciar una clase el cual es un ejemplar de clase u objeto. Para instanciar una clase debemos de hacerlo de la siguiente forma:

Bicicleta clasica=newBicicleta();

Tal como puedes observar, es casi similar a declarar un tipo primitivo, ya que debemos de declarar el tipo, en este caso del tipo Bicicleta, seguido un nombre y  la palabra reservada new. A partir de ello, el objeto clasica, puede hacer uso de las propiedades de la clases o sus métodos, para que puede acceder a cualquiera de ellos se utiliza la nomenclatura del punto que se traduce en:

objeto.propiedad  u objeto.metodo

 

Por ejemplo para acceder a las ruedas de nuestra bicicleta podemos hacer:

clasica.ruedas;

MODULARIZACIÓN 

El ejemplo más común es hacer uso de un equipo de sonido:

modulo1.png

Un equipo de sonido está compuesto, de su lector de CD, su radio, su casetera (modelos más antiguos) y lector de usb; cada uno de los elementos descritos es un todo en si mismo (también se les conoce como clases) que al unirse componen un elemento más complejo que funciona en armonía  (lo que es el equipo de sonido modular), si ocurriese que alguno de estos elementos se averíe, el equipo de sonido seguiría en funcionamiento, podemos decir que estos elementos son módulos del equipo de sonido  y que el mal funcionamiento de un módulo implique que el equipo de sonido deje de funcionar en su totalidad; esto pasa de similar forma en la programación, la modularización segmenta el programa en partes que han de funcionar en armonía siendo su principal ventaja la depuración de errores y reutilización de código ya que se encuentran más focalizados, En JAVA como en todo lenguaje orientado a objetos sucede de igual forma, entonces un programa en Java es un grupo de clases (módulos, funciones o métodos) unidos entre sí y que funcionan como una unidad. Esto se expresa en Java a través del uso de archivos donde se estila que exista solo una clase, un fichero, una clase, esto permite que todo sea más ordenado y se hace uso como una buena práctica, pero también se expresa en crea rutinas re-utilizables dentro de nuestro programa, esto se logra construyendo métodos lo más genéricos posibles de forma que podamos utilizarlos en diferentes instancias de nuestro programa e inclusive utilizarlos en otros programas, reduciendo de esta manera la cantidad de líneas de código que tenemos que escribir, pero no todo es color de rosa.

ENCAPSULAMIENTO

Siguiendo con el ejemplo de equipo de sonido, vemos que funcionan en armonía como un todo, el volumen, puede aumentar el volumen de todo el equipo, pero no puede dar salto hacia otra canción que se encuentre en la lectora de CD, y en viceversa, la lectora de CD no puede subir o bajar el volumen, y ¿Por qué no? pues porque no tendría sentido, bajar o subir el volumen, adelantar una canción o retroceder una desde otro módulo, solo puede hacerse desde su mismo módulo; de similar forma pasa con la programación, imaginemos que en una clase cualquiera instanciamos la clase Bicicletas, ya que hasta el momento no está encapsulada alguna de sus propiedades un usuario cualquiera podría sobrescribir la propiedad rueda diciendo que ahora son 5:

clasica.ruedas=5;

Tan simple como la línea anterior, dado que esto resulta ilógico, también resulta inseguro que el usuario pueda modificar algunas propiedades de forma directa. Para ello debemos de agregar un modificador de acceso de tipo private (más adelante hablaremos de ello), agregando dicho modificador de acceso dicha propiedad es accesible desde la clase pero no desde otra clase. Entonces:

class Bicicleta {
  private int ruedas;
  private int asientos;
  private double largo;
  private double alto;
  String color;
  String material;
  private int peso;

  publicBicicleta(){
    ruedas=2;
    asientos=1;
    largo=1.5;
    alto=0.5;
    color="Amarillo";
    material="Acero";
    peso=20;

  }

}

Hemos colocado el modificador de acceso private solo a aquellos elementos que no deban ser modificables por el usuario, el usuario podrá modificar el color, pero no la cantidad de asientos o ruedas que tenga una bicicleta; pero ¿Cómo podemos tener acceso a estas propiedades?, para ello existen métodos que son como los cables que unen los módulos del equipo de sonido; sin embargo, trataremos esos tópicos en una próxima oportunidad pues este post ya se está extendiendo demasiado.

Java desde Cero Arreglos 2 – Arreglos Bidimensionales

INTRODUCCIÓN

Anteriormente ya hemos explicado que son y como funcionan los arreglos; sin embargo, los arreglos como hemos mencionado son matrices y hasta el momento solo hemos contemplado matrices o arreglos de una sola dimensión, entonces, ¿Qué ocurre con los arreglos de dos dimensiones, o en adelante?, en Java no existen los arreglos bidimensionales por definición, sino que se trata de arreglos dentro de arreglos, siendo que un arreglo de 2 dimensiones puede ser representado como una tabla (aunque no es una tabla) y un arreglo de 3 dimensiones como un cubo y así sucesivamente, siendo que los arreglos de mayores dimensiones representan un verdadero problema al menos en su representación. Un arreglo bidimensional se puede representar de la siguiente forma:

m2.png

DECLARACIÓN

Su declaración de forma implícita sigue la siguiente sintaxis:

int [][] matrix1=new int [4][5];

Quizá una forma sencilla de entenderlo sería que el arreglo principal tendrá 4 sub-arreglos y que cada sub-arreglo tendrá 5 elementos. ¿Podemos declarar un arreglo bidimensional de forma explícita?, sí, pero realmente resultaría muy engorroso, sino observa:

matrix1[0][0]=15;
matrix1[0][1]=21;
matrix1[0][2]=18;
matrix1[0][3]=9;
matrix1[0][4]=15;

matrix1[1][0]=10;
matrix1[1][1]=52;
matrix1[1][2]=17;
matrix1[1][3]=19;
matrix1[1][4]=7;

matrix1[2][0]=19;
matrix1[2][1]=2;
matrix1[2][2]=13;
matrix1[2][3]=17;
matrix1[2][4]=7;

matrix1[3][0]=92;
matrix1[3][1]=13;
matrix1[3][2]=13;
matrix1[3][3]=32;
matrix1[3][4]=41;

También podemos hacerlo de forma explícita de la siguiente forma:

int [][] matrix={{15,21,18,9,15}, {10,52,17,19,7}, {19,2,13,17,7}, {92,13,13,32,41} }

Pero esto resulta quizá sencillo por la cantidad de elementos que alberga el arreglo, imagina ahora si fuera un arreglo de 100×100, definitivamente la forma implícita resulta una mejor opción

RECORRIDO

Obtener una posición específica del arreglo es indicando la posición exacta que estamos buscando:

System.out.println(matrix1[2][0])

Obviamente que debe de existir un valor ya asignado en dicha posición. ¿Cómo podemos recorrer un arreglo bidimensional?, el recorrido se realiza a través de un bucle for anidado, para ello podemos emplear tanto el for convencional como el foreach:

Por ejemplo asignemos los valores a los elementos

for (int i = 0; i < matrix1.length; i++) {
   for(int j =0; j < matrix1[i].length; j++){
      matrix1[i][j]=j+i;
   }
}

Observemos la estructura del bucle for anidado, tanto i como j representan los índices del arreglo y sub-arreglos respectivamente, la estructura se resuelve primero iterando sobre el sub-arreglo manteniendo fijo el valor de i, cuando se ha recorrido todo el sub-arreglo (es decir j) se pasa al siguiente valor de i. Ahora recorramos el arreglo bidimensional pero esta vez haciendo uso del bucle foreach:

for (int[] submatriz : matrix1) {
   for(int elemento : submatriz){
      System.out.println(elemento);
   }
}

Podemos observar que el recorrido es mucho más simplificado solo siempre recordar que deben ser del mismo tipo al elemento que ha de recorrerse.

 

Java desde Cero – Arreglos 1 y ForEach

Bueno ya hemos revisado la mayoría de los bucles, y quizá quede el último que es el forEach; sin embargo, este fue creado para ser empleado en arreglos, eso implica que tenemos que definir que es un arreglo, un arreglo o también conocido como Array, es una estructura de datos del mismo tipo y es empleado para almacenar valores que tienen alguna relación entre sí. Definir un arreglo en Java es como definir una variable o atributo, pero al especificar el tipo lo que hacemos es colocar un par de corchetes [ ] para indicar que estamos definiendo un arreglo, entonces su sintaxis es de la siguiente forma:

tipo[]  nombre=new tipo[cantidad];
double[] tuMatriz=new double[10];

La cantidad (que es la cantidad de elementos que contiene el arreglo) es también denominada longitud; otra característica de los arreglos que estos están ordenados en función de un índice el cual nos permite poder acceder y/o modificar a cada uno de los elementos del arreglo, este índice inicia en la posición 0, en el gráfico podemos observar que si bien es cierto que el arreglo tiene 10 elementos, la última posición es 9, podemos decir entonces que la posición siempre es uno menos que la cantidad de elementos que contenga el arreglo. objects-tenelementarray

Un arreglo también puede inicializarse de forma extensiva, es decir, en la misma línea de la declaración del mismo, podemos enumerar sus elementos:

double[] tuMatriz2={2,3,4,5,6};

 

O luego de haberla inicializado podemos agregar los elementos haciendo referencia a su posición:

double[] tuMatriz3=new double[4];
tuMatriz3[0]=1;
tuMatriz3[1]=2;
tuMatriz3[2]=3;
tuMatriz3[3]=4;

Definitivamente este tipo de procesamiento puede resultar engorroso y es por ello que se hace uso del bucle for, tal como hemos revisado la estructura for, requiere de un inicio una finalización y un paso (incremento o decremento), podemos hacer entonces de la siguiente forma haciendo uso del bucle for:

for(int i=0;i<tuMatriz3.length;i++){
       System.out.println(tuMatriz3[i]);

}

Observemos esta estructura, estamos inicializando en i=0 y establecemos la finalización evaluando si i es menor que la longitud del arreglo, nosotros podemos obtener la longitud del arreglo a través de su propiedad length, el cual nos devuelve un entero, es decir tuMatriz3.length=4, podemos colocar el valor exacto dentro de la estructura, pero ello sería una mala práctica (hard-code) ya que estaríamos incrustando los datos directamente en el código y siendo que si por necesidad del programa cambiamos la longitud del arreglo, tendríamos que buscar la línea exacta donde este se modificó.

El uso del bucle for, también aplica para la inicialización de los elementos que componen un arreglo, esto se da de la siguiente forma:

for(int i =0; i < tuMatriz.length; i++){
     tuMatriz[i]=i;
     System.out.println(tuMatriz[i]);

}

Nosotros ya hemos definido el arreglo y también hemos determinado su longitud (10), y lo que hacemos es que a cada posición i le asignamos el valor de i, luego de esta asignación se imprime el valor ahora contenido en dicha posición.

Dicho esto, podemos ahora poder abordar el bucle foreach, veamos su estructura con los arreglos que ya hemos construido:

for (double elemento : tuMatriz3) {
       System.out.println(elemento);
}

Su estructura se puede traducir  como “por cada elemento de tuMatriz3 hacer:“, se puede observar que el código es más corto siendo el separador el “:“, a lado izquierdo del separador se coloca el elemento que pertenece al arreglo y que debe ser del mismo tipo que el arreglo (en nuestro caso de tipo double) y al lado derecho el arreglo que se ha de recorrer, los beneficiamos más resaltantes son que ya no nos preocupamos de donde partimos y hasta donde llegamos, el bucle ya sabe hasta donde debe llegar. Este tipo de bucle se aprecia más cuando contemplemos los tópicos de colecciones. Bueno eso es todo por el momento.