Java

Objetivo del curso

16/11/2019

¿Que es la programación orientada a objetos?

La programación orientada a objetos (abreviado poo u oop) es un paradigma de la programación que consta de dividir el código de una clase en diferentes unidades individuales llamadas objetos. Los objetos son unidades de memoria que existen en la computadora, y que tienen propiedades, llamadas atributos y acciones u operaciones llamadas métodos.

Todos los ejemplos vistos anteriormente funcionaban en una clase ejecutable llamada Prueba, con una funcion main . A partir de ahora crearemos distintos ficheros y en cada uno de ellos escribiremos el código correspondiente a una clase.

Fijate el siguiente ejemplo:

1       public class Alumno{
2           private String nombre;
3           private String apellido;
5           private int edad;
6
7           public void asistirAClases(){}
8       }

Creamos una clase Alumno, cuyos atributos (propiedades) son nombre, apellido y edad, y su unico método es asistirAClases. Por conveniencia Los nombres de clases en Java se escriben con mayúscula. Cada clase tendrá un constructor al cual se le pasan por parámetros los valores que se le deben asignar a sus atributos. De esta forma, cuando queramos crear un objeto de esta clase, llamaremos al constructor y le pasaremos dichos parámetros. El constructor de la clase Alumnno en este caso quedaría así:

1       public Alumno(String nombre, String apellido, int edad){
2           this.nombre = nombre;
3           this.apellido = apellido;
4           this.edad = edad;
5       }

Y por otro lado, en la clase ejecutable con el método main crearíamos el objeto de la siguiente manera:

1       Alumno a1 = new Alumno("Leonel", "Lima", 20);

Y de la misma forma podemos crear tantos objetos como queramos:

1       Alumno a1 = new Alumno("Leonel", "Lima", 20);
2       Alumno a2 = new Alumno("Enzo", "Diaz", 20);
3       Alumno a3 = new Alumno("Facundo", "Lopez", 27);

Lo mas recomendable para esta guía, así como para el resto de los artículos anteriores, es usar un editor de código y comenzar a escribir los ejemplos aquí presentados. Si bien pueden ser copiados y pegados, lo mejor será escribirlos por cuenta propia para empezar a prácticar y hacer modificaciones y muchas pruebas hasta comprender correctamente como funciona este lenguaje tan poderoso.

A partir de ahora se irá viendo todo en detalle. Esto es solo la introducción...

Volver al submenú...

Referencias

Como ya se mencionó anteriormente, un objeto al igual que una variable, existen en un espacio en memoria y podemos acceder a él para leerlo, usarlo, modificarlo o eliminarlo. Al crear una variable, estamos creando una referencia que indica la posición en memoria donde esta esa variable. Y lo mismo sucede con los objetos.

1       public class Prueba{
2           public static void main(){
3               int array1[] = new int[10];
4               array1[0] = 5;
5               int array2[] = null;
6               array2 = array1;
7               array1[] = new int[20];
8           }
9       }

En este ejemplo, creamos un array1 y le asignamos una referencia a una posición en memoria, usando la palabra new. Luego creamos un array2 y le indicamos null, que significa "nulo", es decir, que no apunta a nada. Al array2 lo igualamos al array1, y lo que estamos haciendo, es indicarle al programa que ahora la referencia de posición en memoria del array2 será la misma que posee array1. Luego, el array1 apuntará a otra dirección en memoria distinta.

¿Y para que sirve saber esto de las referencias en memoria?

Al comparar variables u objetos, lo que hacemos es comparar algo que está guardado en una posición de memoria, con algo que está en otra posición distinta. De esta forma, se explica como funciona la comparación entre objetos.

Si mal no recuerdo, creo que anteriormente no te explique la diferencia entre nulo y vacio. Asique te dejo este meme que encontre en internet para que lo entiendas:

1       public class Prueba{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20);
4               Alumno a2 = null;
5               //a2 no apunta a ninguna direccion en memoria
6               a2 = a1;
7               //ahora a2 apunta a la misma dirección en memoria que a1
8               if(a1 == a2){
9                   System.out.println("Los alumnos son iguales");
10              }
11              //le asignamos a a1 una nueva referencia a una posición en memoria
12              a1 = new Alumno ("Enzo", "Diaz", 20);
13              if(a1 != a2){
14                  System.out.println("Los alumnos son distintos");
15              }
16          }
17      }

Cuando creamos un objeto de una clase, se dice que estamos creando una instancia de esa clase. Para crear una instacia de una clase (o un objeto de una clase) lo que hacemos es indicar la clase seguido del nombre que le vamos a asignar. Luego con la palabra new seguido del nombre de la clase y los parametros, hacemos la invocacion al constructor de esa clase, lo cual veremos en la siguiente leccion.

Esto fue todo sobre referencias.

Volver al submenú...

Variable this

Un constructor es justamente lo que construye a un objeto, con valores que se pasan por parámetro. Sin embargo, Java siempre invoca un constructor por defecto en caso de no invocar uno nosotros mismos.

La variable this se utiliza para diferenciar una variable normal, de un atributo dentro de la clase.

Los constructores de la clase Alumno son:

1       //Constructor por defecto
2       public Alumno(){
3           this.nombre = "";
4           this.apellido = "";
5           this.edad = 0;
6       }
7       //Constructor con parámetros
8       public Alumno(String nombre, String apellido, int edad){
9           this.nombre = nombre;
10          this.apellido = apellido;
11          this.edad = edad;
12      }

Notese que el constructor no devuelve ningún tipo de dato, ni tampoco se indica void. Unicamente indicamos public (ya veremos que significa) seguido del nombre de la clase (recuerda: con mayúscula).

Otra función de la variable this es construir el objeto en el constructor de la siguiente manera:

1       //Constructor por defecto
2       public Alumno(){
3           this("", "", 0);
6       }
7       //Constructor con parametros
8       public Alumno(String nombre, String apellido, int edad){
9           this.nombre = nombre;
10          this.apellido = apellido;
11          this.edad = edad;
12      }

Está terminada la lección sobre constructores y la variable this.

Volver al submenú...

Modificadores de acceso

¡Por fin voy a entender que significa eso de public!¡Ya era hora!

Los modificadores de acceso permiten indicar la accesibilidad que tendrá un método o un atributo de una clase. A continuación una breve explicación y luego pasamos al ejemplo:

Modificador Descripción
public El método o atributo es accesible por cualquiera y desde cualquier lado.
private El método o atributo solo es accesible desde dentro de la clase. Fuera de dicha clase no es visible.
protected Los métodos o atributos de una clase padre serán accesibles desde una clase hija. Se utiliza en herencia

Ejemplo:

1       public class Alumno{
2           private String nombre;
3           private String apellido;
4           public int edad;
5
6           public Alumno(String nombre, String apellido, int edad){
7               this.nombre = nombre;
8               this.apellido = apellido;
9               this = edad;
10          }
11      }

Y ahora la clase ejecutable:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20);
4               //imprimira 20
5               System.out.println(a1.edad);
6               //el atributo edad al ser publico es accesible para cualquier clase
7               //le sumamos 20
8               a1.edad += 20;
9               //imprimira 40
10              System.out.println(a2.edad);
11          }
12      }

Generalmente los atributos suelen declararse como privados para que no puedan ser modificados por otra clase (pero esto no significa que no pueda ser publico), mientras que los métodos suelen ser publicos, salvo que se desee que un método sea visible únicamente en la propia clase.

Si te fijas bien en el ejemplo, la edad del Alumno ha sido declarada como public, por lo que su valor es modificable desde cualquier otra clase. Esto no siempre es conveniente, ya que, como puedes ver en este ejemplo, cualquiera puede modificar la edad de un Alumno sin su consentimiento. Hay que tener esto en cuenta al momento de especificar los modificadores de acceso de los atributos de una clase.

Y esto fue todo sobre modificadores de acceso.

Volver al submenú...

Métodos get y set

Los métodos get y set son métodos que usamos para obtener o modificar un atributo perteneciente a una clase. Suelen llevar un modificador de acceso public y se declaran de la siguiente manera:

El método get:

1       public String getNombre(){
2           return this.nombre;
3       }

El método set:

1       public void setNombre(String nombre){
2           this.nombre = nombre;
3       }

La sintaxis entonces es: modificador de acceso, seguido del tipo de dato que devuelve, get o set y el atributo al cual se busca acceder.

Anteriormente veniamos viendo una clase Alumno con los atributos básicos. Creemos un ejecutable para ver el funcionamiento de get y set.

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("", "Lima", 20);
4               String nombre = a1.getNombre()
5               //imprimira la cadena vacia asignada en el constructor
6               System.out.println(nombre); 
7
8               a1.setNombre("Leonel");
9               nombre = a1.getNombre();
10              //esta vez imprimira el nombre "Leonel"
11              System.out.println(nombre);
12          }
13      }

Esto fue todo sobre los métodos get y set. Es bastante simple.

Volver al submenú...

Métodos y atributos estáticos

Seguramente te da curiosidad el significado de una palabra que se ha visto mucho en los ejemplos utilizados. Esa palabra es static, cuyo fín es el de indicar que un método o atributo es estático. Un atributo que es estático, es un atributo cuyo valor será igual en todos los objetos de esa clase, es decir, que aunque tengamos 100 objetos de una clase, los 100 tendrán el mismo valor en ese atributo.

Se debe tener en cuenta tambien que si un método es estático, los atributos utilizados por dicho método deben ser estáticos, ya que de lo contrario tendremos un error.

Veamos el siguiente ejemplo, donde agregaremos a la clase Alumno, un sueldo por el plan Progresar:

1       public class Alumno{
2           private String nombre;
3           private String apellido;
4           private int edad;
5           private static double sueldoProgresar = 1050;
6
7           public Alumno(String nombre, String apellido, int edad){
8               this.nombre = nombre;
9               this.apellido = apellido;
10              this.edad = edad;
11          }
12          
13          public static double getSueldoProgresar(){
14              return sueldoProgresar;
15          }
16
17          public static void setSueldoProgresar(double sueldo){
18              this.sueldoProgresar = sueldo;
19          }
20      }

Notese que, por un lado, el atributo sueldoProgresar no aparece en el constructor, y por otro lado, que en el método setSueldoProgresar he colocado el nombre de la clase seguido del nombre del atributo que quiero modificar. Dicho atributo tiene un valor que será el mismo en cualquier objeto de la clase Alumno.

Entonces, en la clase ejecutable:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20);
4               Alumno a2 = new Alumno("Enzo", "Diaz",, 20);
5               System.out.println(a1.sueldoProgresar);
6               System.out.println(a2.sueldoProgresar);
7
8               Alumno.setSueldoProgresar(1250);
9
10              System.out.println(a1.sueldoProgresar);
11              System.out.println(a2.sueldoProgresar);
12          }
13      }

Creamos dos objetos de la clase Alumno e imprimimos el sueldo de cada uno. En ambos casos se imprimirá el mismo valor.

Luego cambiamos el valor del sueldo con el método set. Como podrás ver, para acceder a este método, he colocado el nombre de la clase seguido del método, y le paso por parámetro el valor. Mas tarde, al volver a imprimir el sueldo de ambos alumnos, el valor impreso será el mismo.

Esto fue todo sobre los métodos y atributos estáticos.

Volver al submenú...

Polimorfismo

El polimorfismo es una de las características de la programación orientada a objetos. Permite que el comportamiento de un objeto sea distinto al comportamiento de otro objeto, aunque estos tengan el mismo nombre.

Basicamente, nos permite que las clases hijas o subclases implementen un método de la clase padre de forma distinta. Es decir, el método de la subclase lleva el mismo nombre, los mismos parámetros, y devuelve el mismo tipo de dato que el método en la superclase, pero ambos funcionan de una forma distinta.

Siguiendo el ejemplo que veniamos viendo, en la clase persona agregaremos un método llamado tomarRecreo, el cual se da en un horario específico cada día de la semana. Sin embargo, sabemos que el recreo de un Alumno es distinto al de un Profesor.

Entonces, el mismo método reescrito en la clase Alumno quedaría así:

1       public class Alumno extends Persona{
2           private static double sueldoProgresar = 1050;
3           private String carrera;
4
5           public Alumno(String nombre, String apellido, int edad, String carrera){
6               super(nombre, apellido, edad);
7               this.carrera = carrera;
8           }
9            
10          public void rendirExamen(){
11              //Conjunto de instrucciones
12          }
13
14          public void tomarRecreo(){
15              irAlBanio();
16              comprarEnQuiosco();
17              salirAlPatio();
18          }
19
20          //la declaracion de cada metodo
21
22          public void irAlBanio(){ }
23          public void comprarEnQuisco(){ }
24          public void salirAlPatio(){ }    
25      }

Y en la clase Profesor:

1       public class Profesor extends Persona{
2           private int legajo;
3           private String instituto;
4
5           public Profesor(String nombre, String apellido, int edad, int legajo, String instituto){
6               super(nombre, apellido, edad);
7               this.legajo = legajo;
8               this.instituto = instituto;
9           }
10
11          public void tomarExamen(){
12              //Conjunto de instrucciones
13          }
14
15          public void tomarRecreo(){
16              irSalaProfesores();
17              tomarUnCafe();
18              ordenarApuntes();
19          }
20
21          //declaracion de metodos
22
23          public void irSalaProfesores();
24          public void tomarUnCafe();
25          public void ordenarApuntes();
26      }

Quizás no es el ejemplo mas claro, o es demasiado resumido. Pero si consideras que el método existe en la clase persona, que tanto los nombres como el tipo de dato devuelto es el mismo, y que todos funcionan de forma distinta, ya habrás entendido el concepto del polimorfismo.

Al declarar un método en una subclase que ya existe en la superclase, y acceder a el, automáticamente la computadora entiende que el método esta sobreescrito, y que funciona distinto a como funciona el de la superclase, e ignorará este último.

Por el contrario, si un método que existe en la superclase y que no fue reescrito en la subclase, al intentar acceder a el, estaremos accediendo al método de la superclase.

Esto fue todo sobre polimorfismo.

Volver al submenú...

Función toString

Cuando estamos trabajando con clases, el método toString puede resultarnos de mucha utilidad. Este método sirve para mostrar la información completa de un objeto. Pero debido a que es un método que, al igual que equals(), se hereda de la clase java.lang.Object, debemos sobreescribir el método.

Sirve básicamente para mostrar los metadatos de un objeto, y podemos usarlo para mostrar el mensaje en la forma que queramos. Ejemplo:

1       public class Alumno extends Persona{
2           private static double sueldoProgresar = 1050;
3           private String carrera;
4
5           public Alumno(String nombre, String apellido, int edad, String carrera){
6               super(nombre, apellido, edad);
7               this.carrera = carrera;
8           }
9            
10          public String toString(){
11              String mensaje = "El nombre completo del alumno es " +nombre+ " " +apellido+ " y tiene " +edad+ " años.";
12              return mensaje;
13          }
14      }

Y en la clase ejecutable recibiremos este mensaje y lo mostraremos en pantalla de la siguiente manera:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20, "Sistemas");
4               Alumno a2 = new Alumno("Enzo", "Diaz", 20, "Sistemas");
5
6               System.out.println(a1.toString());
7               System.out.println(a2.toString());
8           }
9       }

El resultado sería el siguiente:

El nombre completo del alumno es Leonel Lima y tiene 20 años.
El nombre completo del alumno es Enzo Diaz y tiene 20 años.

Un detalle antes de finalizar esta simple lección. Si el método fue definido como en el primer ejemplo en la clase Alumno, al momento de imprimir la información del objeto, podremos acceder al método toString sin tener que invocarlo. De esta forma podríamos modificar el ejemplo anterior y el resultado sería el mismo:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20, "Sistemas");
4               Alumno a2 = new Alumno("Enzo", "Diaz", 20, "Sistemas");
5
6               System.out.println(a1);
7               System.out.println(a2);
8           }
9       }

Notese que en las líneas System.out.println únicamente coloque entre los paréntesis el nombre del objeto al que quiero acceder para mostrar su información. De esta forma estoy invocando al método sin tener que indicarlo formalmente.

Esto fue todo sobre el método toString.

Volver al submenú...

Comparación entre objetos

Cuando hablamos sobre las referencias en Java, habiamos visto que podiamos comparar tanto variables como ojetos, verificando que la dirección de memoria a la que apuntaran sea la misma. Sin embargo esto es poco práctico para la mayoria de sistemas que vayamos a realizar. Mucho mejor es poder comparar ciertos atributos específicos de dos clases distintas. En este artículo voy a explicarte como se hace.

Recordemos el funcionamiento del método equals, que es heredado por la superclase java.lang.Object, pues este método puede ayudarnos a comparar objetos. Al igual que el método toString puede ser sobreescrito y utilizado, podemos hacer lo mismo con el método equals, para comparar, por ejemplo, si el nombre y apellido de un alumno es igual que el nombre y apellido de otro.

Entonces, en la clase Alumno hariamos lo siguiente:

1       public boolean equals(Alumno a){
2           if(a.getNombre().equals(nombre) && a.getApellido().equals(apellido)){
3               return true;
4           }
5           else{
6               return false;
7           }
8       }

Como puedes ver, estamos indicando una doble condición dentro de la estructura if, y para cada condición estamos comparando el nombre de un alumno con el nombre de otro alumno pasado por parámetro. Si mal no recuerdo, en ninguno de los ejemplos anteriores habiamos concatenado dos métodos. Pues esta es la forma de hacerlo.

Los métodos, al igual que los textos y variables, pueden ser concatenados. El orden en el que se ejecutan estos métodos es de izquierda, a derecha. Es decir, primero se obtiene el nombre del alumno pasado por parámetro usando getNombre y luego se usa equals para compararlo con el nombre del alumno.

Y de esta forma, en la clase ejecutable, podremos llamar a ese método:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20, "Sistemas");
4               Alumno a2 = new Alumno("Enzo", "Diaz", 20, "Sistemas");                        
5
6               if(a1.equals(a2)){
7                   System.out.println("Los alumnos son iguales");
8               }
9               else{
10                  System.out.println("Los alumnos son distintos");
11              }
12          }
13      }

De la misma forma en que se comparan los nombres y apellidos, podriamos modificar el método para comparar si pertenecen a la misma carrera. Te lo dejo como tarea...

También podemos comparar si un objeto es mayor que otro, en lo que respecta a la edad por supuesto. Esto ya no lo haremos con equals, ya que este método compara cadenas de caracteres. Lo que haremos sera implementar una interfaz. Que bonito... Otra palabra nueva... No te preocupes mucho por entender que significa. Mas adelante te explicaré lo que es, por el momento solo haz lo que yo.

Para implementar una interfaz, haremos algo similar a lo que haciamos con herencia:

1       public class Alumno implements Comparable<Alumno>

Ahora podremos implementar un método llamado compareTo. Entonces en la clase Alumno vamos a implementar el método para hacer una comparación de edades entre dos alumnos:

1       public int compareTo(Alumno a){
2           //-1 indica que el objeto pasado por parametro es mayor
3           int estado = -1;
4           if(edad==a.getEdad()){
5               //tienen la misma edad
6               estado = 0;
7           }
8           else if(edad>a.getEdad()){
9               //el objeto 1 es mayor que el pasado por parametro
10              estado = 1;
11          }
12          return estado;
13      }

Y en la clase ejecutable lo usaremos de la siguiente forma:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno a1 = new Alumno("Leonel", "Lima", 20, "Sistemas");
4               Alumno a2 = new Alumno("Enzo", "Diaz", 20, "Sistemas");
5
6               if(a1.compareTo(a2)==0){
7                   System.out.println("Los alumnos tienen la misma edad");
8               }
9               else{
10                  if(a1.compareTo(a2)==1){
11                      System.out.println("El alumno 1 es mayor que el alumno 2");
12                  }
13                  else{
14                      System.out.println("El alumno 2 es mayor que el alumno 1");
15                  }
16              }
17          }
18      }

Si bien no es la única forma de comparar objetos, son las más sensillas, dado que sobreescribimos métodos que ya existen, o incluso puedes usar el método sin sobreescribirlo, leyendo la documentación necesaria. También puedes crear tu propio método u algoritmo de comparación. En programación existen miles de formas de hacer lo mismo de maneras distintas.

Esto fue todo sobre métodos de comparación de objetos.

Volver al submenú...

Array de objetos

Habíamos visto que un array es una colección de datos. ¿Acaso un objeto de una clase no es un dato? Claro que sí. Entonces podremos crear un arreglo en el cual guardemos diferentes objetos. Pero cuidado. Una cosa es un array de tipo Object, y otra cosa es un array de tipo Alumno (usando la clase Alumno como ejemplo, este array solo guardará objetos de la clase Alumno, y no de otra clase).

Al obtener la posición del arreglo en la cual hay se encuentra uno de los objetos, podremos invocar a los métodos de ese objeto. Veamos el ejemplo:

1       public class EjecutableApp{
2           public static void main(String[] args){
3               Alumno arreglo[] = new Alumno[3];
4               arreglo[0] = new Alumno("Leonel", "Lima", 20, "Sistemas");
5               arreglo[1] = new Alumno("Enzo", "Diaz", 20, "Sistemas");
6               arreglo[2] = new Alumno("Facundo", "Lopez", 27, "Sistemas");
7
8               //Vamos a hacer la suma entre sus edades
9
10              int suma = 0;
11              for(int i = 0; i > arreglo.length; i++){
12                  suma += arreglo[i].getEdad();
13              }
14              System.out.println("La suma de las edades es "+suma);
15          }
16      }

En un caso de la vida real, sumar las edades de los alumnos no tiene el menor sentido. Pero al menos el ejemplo servirá para explicar como funciona la invocación de métodos mediante un arreglo de objetos.

Es tu turno de darle creatividad al asunto...

Volver al submenú...

Listas

En la programación orientada a objetos, o al menos en Java, es muy común el uso de las listas, incluso antes que los arreglos. Las listas o arraylist, como su nombre lo indica, están basadas en los arreglos, pero presentan algunas ventajas con respecto a estos últimos.

Inicialmente, en su declaración, no es necesario especificar cuantas posiciones son necesarias, sino que simplemente agregamos información sin preocuparnos por su tamaño. Su declaración es la siguiente:

1       List<String> ejemploLista = new ArrayList<String>();

De esta forma de declara una lista que almacenara datos de tipo String. Sin embargo, las listas se encuentran en una librería de Java, por lo que habrá que importarlas. Para ello, escribirás en la primer línea de código (antes de declarar la clase) lo siguiente:

1       import java.util;

Y ahora sí, podremos comenzar a agregar registros en la lista. Vamos a crear una lista de tipo Alumno en nuestra clase ejecutable, crearemos 3 alumnos, y los agregaremos a la lista:

1       import java.util;
2       public class EjecutableApp(){
3           public static void main(String[] args){
4               List<Alumno> ejemploLista = new ArrayList<Alumno>();
5
6               Alumno a1 = new Alumno("Leonel", "Lima", 20, "Sistemas");
7               Alumno a2 = new Alumno("Enzo", "Diaz", 20, "Sistemas");
8               Alumno a3 = new Alumno("Facundo", "Lopez", 27, "Sistemas");
9
10              ejemploLista.add(a1);
11              ejemploLista.add(a2);
12              ejemploLista.add(a3);
13          }
14      }

El método add sirve para agregar un registro en la lista. Y al igual que este, tenemos muchos otros métodos que pueden resultar muy beneficiosos para trabajar en diversos sistemas.

Para obtener la cantidad de elementos de la lista se utiliza:

1       ejemploLista.size();

Para obtener una de las variables u objetos de la lista en un determinado índice:

1       ejemploLista.get(0);

Para eliminar un determinado elemento:

1       ejemploLista.remove(0);

Para imprimir la lista completa:

1        System.out.println(ejemploLista);

Para imprimir cada elemento de la lista de forma individual:

1       for(int i = 0; i < ejemploLista.size(); i++){
2           system.out.println(ejemploLista.get(i));
3       }

Y esto fue todo sobre listas. Es más sencillo aprender el tema practicando que leyendo. Pon rienda suelta a tu imaginación...

Volver al submenú...

Python

  • Proximamente...

HTML

  • Proximamente...