Java y otras yerbas...

cdcelja2.jpeg

La idea es abrir un tópico exclusivo de este lenguaje para compartir dudas, consejos, librerías o rutinas útiles.

Hace no mucho en un tópico se abrió la discusión de ¿por qué Java no tenía variables del tipo unsigned?

Si bien uno es consciente de que el tamaño de las variables no necesariamente son fijas (como por ej. C y según la arquitectura sobre la que se trabaje), debido a la base de electrónico que uno tiene, casi siempre trata de ver las cosas más acorde con el bajo nivel (obviamente en la mayoría de los casos no se puede).

Como mencionaba en ese tópico, para manejar el puerto serie existe una librería llamada RxTx que brinda todas los métodos necesarios para hacer funcionar el puerto. Sin embargo hay un método de lectura que devuelve una variable del tipo "byte", esta variable va de -128 a 127, por lo tanto si se usa ese método con un uC que envía datos que van de 0 a 255, se va a encontrar con problemas.

Existen dos alternativa:

1- Jugar con el resultado negativo y convertirlo a positivo con una variable del tipo short usando una máscara.
2- Usar el método de lectura que devuelve un "int".

Yo muy acostumbrado a bajo nivel, en un principio desestimé la 2da solución pensando que el tipo de datos que enviaba/recibía no correspondían por el tipo de variables, por ese motivo opté por la solución 1.

La solución 1 funciona bien, pero es ... diriamos.... "poco feliz", hace lo que tiene que hacer, pero no de la mejor forma.

Al probar la solución dos, comprobé que efectivamente funcionaba, yo enviaba 200 y recibía sin hacer nada "raro" 200.

En otro lugar donde creo que hubiera sido útil el uso de "unsigned" es en el manejo de imágenes, por ej. para trabajar con una imagen blanco y negro de 8 bits, no se puede usar la variable de tipo "byte", por tal motivo hay que recurrir al uso de variables del tipo "short" que son mucho más grandes y por ende el resultado de trabajar con ese tipo de variables es más laborioso en cuanto al procesamiento.

En cambio por ej. en C#, la variable de tipo "byte" es "unsigned" (0 a 255), lo que permite por ej. un mejor manejo de imágenes.

Ok, me podrán decir: "no uses java para procesar imágenes, usá una librería de bajo nivel en C/C++ (JNI)". Es cierto, lo ideal es hacer eso, pero resulta muy engorroso hacer ese tipo de librerías (el que lo hizo, lo sabrá muy bien) y encima este tipo de soluciones no te permiten realizar pruebas rápidas en Java mismo.

Bue... con esto inicio la discusión. :D
 
Si bien uno es consciente de que el tamaño de las variables no necesariamente son fijas (como por ej. C y según la arquitectura sobre la que se trabaje), debido a la base de electrónico que uno tiene, casi siempre trata de ver las cosas más acorde con el bajo nivel (obviamente en la mayoría de los casos no se puede).

Bien... acá hay que aclarar algunas cosas propias de Java:
Dado que Java es un lenguaje multiplataforma y del tipo compilar-una-vez y ejecutar-en-cualquier-parte, necesariamente sus tipos de datos son - a diferencia del C - de tamaño fijo y definido en las especificaciones del lenguaje. Por ejemplo:

  • Los bytes tienen 8 bits.
  • Los short y los char tienen 16 bits.
  • Los int tienen 32 bits.
  • y así siguiendo.
Para mas info, ver ACA y ACA.

En la versión 8 de Java, hay referencias a conversiones unsigned, lo que hace suponer que hay tipos unsigned, pero la verdad es que no encontré mas información de aplicación directa.


Como mencionaba en ese tópico, para manejar el puerto serie existe una librería llamada RxTx que brinda todas los métodos necesarios para hacer funcionar el puerto. Sin embargo hay un método de lectura que devuelve una variable del tipo "byte", esta variable va de -128 a 127, por lo tanto si se usa ese método con un uC que envía datos que van de 0 a 255, se va a encontrar con problemas.
Existen dos alternativa:

1- Jugar con el resultado negativo y convertirlo a positivo con una variable del tipo short usando una máscara.
2- Usar el método de lectura que devuelve un "int".

Yo muy acostumbrado a bajo nivel, en un principio desestimé la 2da solución pensando que el tipo de datos que enviaba/recibía no correspondían por el tipo de variables, por ese motivo opté por la solución 1.

La solución 1 funciona bien, pero es ... diriamos.... "poco feliz", hace lo que tiene que hacer, pero no de la mejor forma.

Al probar la solución dos, comprobé que efectivamente funcionaba, yo enviaba 200 y recibía sin hacer nada "raro" 200.
Esto es algo cuestionable... :confused:
Dado que los bytes de Java son de 8 bits y los de los µC también lo son, si la interfaz de I/O entre ellos está bien diseñada (me refiero al hardware), no existe problema de ningún tipo en la transferencia. El campo de representación de un tipo byte y de un unsigned byte es el mismo en cuanto a la "cantidad de números" disponibles, y el que sea positivo o negativo es solo una cuestión que afecta a las operaciones aritméticas.
Pero claro, la interpretación que hace Java es en complemento a 2 y la que hace el C con los unsigned no usa el complemento. Esto es, si mando un byte con el valor 200 desde C a Java, lo que reciba Java lo va a interpretar como -54, aun cuando el patrón de bits es exactamente el mismo.

Entonces, los problemas surgen cuando queremos operar matemáticamente o a nivel de bits con estos valores que están fuera del rango del complemento a 2 para los ocho bits del byte, y por ese motivo hay que extenderlo a un tipo "mas grande" como podría ser el short o el int.
 
En la versión 8 de Java, hay referencias a conversiones unsigned, lo que hace suponer que hay tipos unsigned, pero la verdad es que no encontré mas información de aplicación directa.

Yo también leí algo, pero después encontré que en realidad era solo una definición que lo que hacía era transformar una variable signada mayor en un unsigned de menor rango, o sea lo mismo que usar un short para un valor de 8bit sin signo.

Esto es algo cuestionable... :confused:
Dado que los bytes de Java son de 8 bits y los de los µC también lo son, si la interfaz de I/O entre ellos está bien diseñada (me refiero al hardware), no existe problema de ningún tipo en la transferencia. El campo de representación de un tipo byte y de un unsigned byte es el mismo en cuanto a la "cantidad de números" disponibles, y el que sea positivo o negativo es solo una cuestión que afecta a las operaciones aritméticas.
Pero claro, la interpretación que hace Java es en complemento a 2 y la que hace el C con los unsigned no usa el complemento. Esto es, si mando un byte con el valor 200 desde C a Java, lo que reciba Java lo va a interpretar como -54, aun cuando el patrón de bits es exactamente el mismo.

Exacto.

Entonces, los problemas surgen cuando queremos operar matemáticamente o a nivel de bits con estos valores que están fuera del rango del complemento a 2 para los ocho bits del byte, y por ese motivo hay que extenderlo a un tipo "mas grande" como podría ser el short o el int.

Sin dudas, usá una variable de mayor tamaño ya, en la mayoría de los casos no trae demasiados inconvenientes hacer eso.

Por cierto, yo uso el entorno que brinda Oracle, el Netbeans, es bastante completo para ser una herramienta gratuita, la otra alternativa (Eclipse) no llegué a usarla.
 
Uhhhh... pero vos sos muuuyyyy sofisticado!!!!
Yo uso el Notepad++ para editar y el compilador del JDK desde una terminal... o a veces uso el ANT de Apache con los guiones XML escritos a pedal.
 
Para levantar un poco, voy tratar de subir un mini tutorial, rápido y conciso, para ayudarlos a dar el primer paso en este lenguaje, más que nada para los que ya manejan C.

El tutorial lo voy hacer en netbeans, que es el entorno oficial de Oracle, para programar se va a necesitar tanto el entorno, como las librerías de desarrollo en java llamdas jdk. Para simplificar las cosas, Oracle nos ofrece la posibilidad de bajar el entorno y las librerías en un solo paquete instalador (tanto en windows como en linux), o sea que la cosa es bien fácil:

http://www.oracle.com/technetwork/articles/javase/jdk-netbeans-jsp-142931.html

Con el entorno ya instalado, empecemos con un ejemplo en consola fácil. Pasos:

1- Archivo -> Nuevo Proyecto
2- Java -> Aplicación Java -> Siguiente
3- Nombre del proyecto -> EjemploConsolaUno

Al crear el proyecto, nos encontramos que el netbeans nos creo una clase nueva con el nombre que le dimos al proyecto y que contiene el main del proyecto, es decir el código se empieza a ejecutar desde ahí.

Captura.PNG

Lo primero que vamos hacer, es escribir un "Hola Mundo!" y ejecutar.

PHP:
package ejemploconsolauno;

public class EjemploConsolaUno {

    public static void main(String[] args) {
        // TODO code application logic here
        
        System.out.println("Hola Mundo!");
    }    
}

Captura2.PNG

Sin entrar en demasiados detalles, para imprimir en consola, basta con usar el método "System.out.println" como el típico "printf" de C.

Ahora, agreguemos algo al código, por ej. la asignación de dos variables, su suma y el resultado.

PHP:
package ejemploconsolauno;

public class EjemploConsolaUno {

   
    public static void main(String[] args) {
        // TODO code application logic here
        
        int valor1, valor2;
        valor1=1;
        valor2=3;
        
        System.out.println("Hola Mundo!, el resultado de la suma es: "+(valor1+valor2));
    }    
}

Resultado:

Código:
run:
Hola Mundo!, el resultado de la suma es: 4
BUILD SUCCESSFUL (total time: 0 seconds)

Como verán, el manejo de los Strings resulta muchísimo más sencillo que en C, por ej. directamente agregando "Mi string "+valor_entero, la salida que se obtiene es un nuevo String donde el valor entero fue agregado y convertido en forma automática. Es decir el código anterior es lo mismo que realizar lo siguiente:

PHP:
package ejemploconsolauno;

public class EjemploConsolaUno {

   
    public static void main(String[] args) {
        // TODO code application logic here
        
        int valor1, valor2;
        valor1=1;
        valor2=3;
        
        String mensaje_salida="Hola Mundo!, el resultado de la suma es: "+(valor1+valor2);
        System.out.println(mensaje_salida);
    }    
}

El resultado es exactamente el mismo, solo que se utilizó una variable del tipo String de intermediaria.

Otra diferencia con C, es que por ej. se puede declarar una variable en cualquier parte del código y no necesariamente en el principio, incluso esas declaraciones pueden ser exclusivas de un bloque como un for.

Agreguemos algo más interesante, un ingreso por teclado, para lo cual usaremos una variable del tipo Scanner (hablo de variables, para de momento no confundirnos con clases/objetos). Siguiendo con el ejemplo, agregamos la siguiente línea:

PHP:
Scanner entradaEscaner = new Scanner (System.in);

De inmediato vamos a ver que el IDE (entorno de programación, es decir Netbeans), nos advierte que algo va mal, es decir que escribimos cualquier verdura o que falta algo:

Captura3.PNG

Si hacemos click en la advertencia, el IDE nos muestra las opciones que tenemos para solucionar el problema (si, es recontra mágico si uno viene de programar en C, ni te cuento en Assembler :LOL:). Como se vé en la imagen, la primera opción que nos dá, es agregar la librería que contiene la "variable" Scanner, si hacemos click, automáticamente nos agregará la siguiente línea arriba de código:

PHP:
import java.util.Scanner;

Y el mensaje de error desaparecerá. Es decir, que automáticamente se agregó la librería necesaria para poder usar el Scanner, en C es como si hubiera agregado el .h en forma automática.

Ahora que tenemos el Scanner disponible, su uso resulta bien sencillo como se verá en el siguiente código:

PHP:
package ejemploconsolauno;

import java.util.Scanner;

public class EjemploConsolaUno {

   
    public static void main(String[] args) {
        // TODO code application logic here
        
        int valor1, valor2;
        valor1=1;
        valor2=3;
        
        Scanner entradaEscaner = new Scanner (System.in);
        String mensaje_salida= entradaEscaner.nextLine();
        
        mensaje_salida+=" "+(valor1+valor2);
        System.out.println(mensaje_salida);
    }    
}

Al ejecutar, en la ventana de salida deberemos ingresar un mensaje y presionar enter, por ej. yo ingresé "Prueba teclado!", dando como resultado:

Código:
run:
Prueba teclado!
Prueba teclado! 4
BUILD SUCCESSFUL (total time: 7 seconds)

El primer "Prueba teclado!" es el texto que ingresé, en cambio el segundo es el resultado de la impresión en pantalla en conjunto con la suma.

Agreguemos un for para repetir el mensaje varias veces y señalando la repetición:

PHP:
package ejemploconsolauno;

import java.util.Scanner;

public class EjemploConsolaUno {

   
    public static void main(String[] args) {
        // TODO code application logic here
        
        int valor1, valor2;
        valor1=1;
        valor2=3;
        
        Scanner entradaEscaner = new Scanner (System.in);
        String mensaje_salida= entradaEscaner.nextLine();
        
        mensaje_salida+=" "+(valor1+valor2);
  
        for(int cont=1; cont<11; cont++)
        {
            System.out.println("Repetición nº: "+cont+" - "+mensaje_salida);
        }
    }    
}

Resultado:

Código:
run:
Resultado de la suma:
Repetición nº: 1 - Resultado de la suma: 4
Repetición nº: 2 - Resultado de la suma: 4
Repetición nº: 3 - Resultado de la suma: 4
Repetición nº: 4 - Resultado de la suma: 4
Repetición nº: 5 - Resultado de la suma: 4
Repetición nº: 6 - Resultado de la suma: 4
Repetición nº: 7 - Resultado de la suma: 4
Repetición nº: 8 - Resultado de la suma: 4
Repetición nº: 9 - Resultado de la suma: 4
Repetición nº: 10 - Resultado de la suma: 4
BUILD SUCCESSFUL (total time: 6 seconds)

Como dato interesante, si quisieramos usar la variable "cont" luego del for, nos dariamos cuenta que ya no se encuentra definida, es decir que esa variable que se definió dentro del for, nada más sirve para ser utilizada en ese bloque.

Para finalizar con el ejemplo, agreguemos un if, si la variable "cont" es mayor a 5, que imprima otro mensaje:

PHP:
package ejemploconsolauno;

import java.util.Scanner;

public class EjemploConsolaUno {

   
    public static void main(String[] args) {
        // TODO code application logic here
        
        int valor1, valor2;
        valor1=1;
        valor2=3;
        
        Scanner entradaEscaner = new Scanner (System.in);
        String mensaje_salida= entradaEscaner.nextLine();
        
        mensaje_salida+=" "+(valor1+valor2);
        
        for(int cont=1; cont<11; cont++)
        {
            if(cont<6)
            {
                System.out.println("Repetición nº: "+cont+" - "+mensaje_salida);
            }
            else
            {
                System.out.println("Repetición nº: "+cont+" - Repetición mayor a 5");
            }            
        }
    }    
}

Código:
run:
Resultado de la suma:
Repetición nº: 1 - Resultado de la suma: 4
Repetición nº: 2 - Resultado de la suma: 4
Repetición nº: 3 - Resultado de la suma: 4
Repetición nº: 4 - Resultado de la suma: 4
Repetición nº: 5 - Resultado de la suma: 4
Repetición nº: 6 - Repetición mayor a 5
Repetición nº: 7 - Repetición mayor a 5
Repetición nº: 8 - Repetición mayor a 5
Repetición nº: 9 - Repetición mayor a 5
Repetición nº: 10 - Repetición mayor a 5
BUILD SUCCESSFUL (total time: 4 seconds)

Como verán, el uso del for y del if es muy similar que en C. Por último los tipos de variables son también similares a los que se encuentran en C, salvo que no existen variables no signadas, aparecen la variable tipo "String" y variables boolaneas (true/false).
 
La idea ahora es agregar el concepto de clases y objetos.

Teoría muy básica:

Sin ir demasiado a los detalles, una clase nos permite definir variables y métodos (método=funciones) en un cierto bloque de código, en cambio un objeto es la implementación de esa clase en forma de "variable", en otras palabras la clase es la que permite definir la característica de un objeto.

Una de las ventajas que nos brinda usar clases/objetos, es que se puede encapsular de forma muy efectiva rutinas de código, ¿que significa eso de encapsular? trabajar en forma bien modular con piezas simples para luego combinarlas con otras piezas simples y formar algo más complejo. La característica más importante del encapsulamiento es "aislar" el núcleo de esa pieza y que no se vea afectado por el entorno externo. A ver... suena demasiado raro todo eso, en términos de código, evita que las variables/métodos de un objeto sean accesibles desde el exterior, aisla esos componentes del objeto. La ventaja que trae el encapsulamiento es implementar un código seguro y de muy fácil mantenimiento a futuro.

Volvamos al código para que se entienda, creémos un proyecto nuevo llamado "EjemploConsolaDos" tal como se vió en el mensaje anterior.

En este ejemplo no se me ocurrió mejor idea que hacer cálculos básicos de estadísticas (que divertido!! :LOL:). La idea es a partir de una serie de datos númericos (pueden tener decimales), calcular tres cosas:

1- Esperanza (promedio).
2- Varianza.
3- Desvío estándar.

La esperanza es simplemente calcular el promedio, es decir sumar todos los elementos y dividirlo por la cantidad de elementos (nada raro).

La varianza es un poco más complejo:

41e992d75f4ae308a89339054f2b2578.png


La traducción de esa cosa fea es:

[LATEX]Varianza=\frac{1}{n}.\sum_{i=1}^{n}\left(Valor-Esperanza\right)^2[/LATEX]

Por último, el desvío es la raíz cuadrada de la varianza (fácil!).

Bue... volvamos al código... como primer paso en nuestro proyecto creado, es agregar un paquete nuevo llamado "Estadística", para realizar eso, presionamos botón derecho sobre "Source Package" (en español será paquetes fuentes), tal como se vé en esta imagen:

Package.png

Nos pedirá ingresar el nombre del paquete, pondremos "Estadística". Un paquete permite agregar muchas clases separadas, por lo tanto si bien para este ejemplo solo utilizaremos una clase, a futuro podremos seguir agregando clases de estadística en ese paquete y hacerlo más complejo. Ok... la estadística es aburrida y es poco probable que hagamos algo de eso, pero supongamos que en vez de estadística sea un paquete "Archivo" o "Ethernet", la idea se mantiene.

Ahora en ese paquete, agreguemos la clase "Esperanza", para lo cual hacemos click derecho sobre el paquete -> nuevo -> clase java. Nos creará una nueva clase llamada Esperanza.

ClaseNueva.PNG

Empecemos con la clase, definamos las variable que tendrá:

. Esperanza
. Varianza
. Desvío estándar
. Los datos utilizados para calcular las variables anteriores (esta variable deberá ser un vector, ya que tendrá varios valores).

Estas variables a definir, podrán ser vistas en tooooda la clase, es como si fueran variables globales... pero solo a nivel de clases, es decir todo los elementos que estén en la clase, incluyendo los métodos, podrán acceder a estas variables.

Por otro lado, a la hora de definir variables (o incluso métodos), tenemos la opción de que sean accesibles o no desde el exterior (el encapsulamiento que mencioné antes). Yo recomiendo trabajar todo en forma bien local y mediante métodos acceder a las variables en forma indirecta (que es lo que voy hacer en este ejemplo). Para que una variable sea accesible desde el exterior, deberá ser definida como "public", en cambio para que solo pueda ser accedida desde la clase, la variable deberá ser definida como "private". Entonces la definición de variables quedará de la siguiente forma:

PHP:
package Estadistica;


public class Esperanza {
    private double esperanza=0;
    private double varianza=0;
    private double desvio_estandar=0;
    private double datos[];
}

Todas son privada y del tipo double (decimales, es un flotante de doble precisión). Los datos serán un vector y como no se sabe el tamaño de los datos que tendrá, de momento no hará falta definirlo.

Ahora implementaremos los métodos para realizar el cálculo de c/variable, al igual que las variables, estós métodos serán privados, ya que no es necesario que sean accedidos desde el exterior.

PHP:
package Estadistica;


public class Esperanza {
    private double esperanza=0;
    private double varianza=0;
    private double desvio_estandar=0;
    private double datos[];

    private void CalcularEsperanza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=this.datos[cont];
        }
        
        this.esperanza=aux/(double)(this.datos.length);
    }

    private void CalcularVarianza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=Math.pow(this.datos[cont]-this.esperanza, 2);
        }
        
        this.varianza=aux/(double)(this.datos.length);
    }
    
    private void CalcularDesvioEstandar()
    {
        this.desvio_estandar=Math.sqrt(this.varianza);
    }
}

Creo que los métodos son bastante simples de entender en función de la fórmula que puse arriba. Se utilizaron métodos de la clase "Math", pow (potencia) y sqrt (raíz), la clase Math no requiere agregar ningún paquete adicional.

Algo nuevo que aparece es "this." c/vez que se accede a una variable "global" de la clase. Ese "this." no es obligatorio agregarlo, pero es útil para diferenciar las variables "globales" de la clase con las variables locales de los métodos, por tal motivo les recomiendo su uso.

Hasta este punto tenemos los métodos para calcular las variables, pero nos falta el ingreso de datos, la llamada a esos métodos de cálculos y por último obtener los resultados de las variables desde el exterior.

Para el ingreso de datos, se podría utilizar un método para asignar los datos, sin embargo a veces resulta más elegante usar lo que se llama "constructor" para inicializar variables desde el exterior. Un constructor es simplemente un método que tiene el mismo nombre que la clase y solo pude ser llamado durante la creación del objeto. Siguiendo con el ejemplo:

PHP:
package Estadistica;

public class Esperanza {
    private double esperanza=0;
    private double varianza=0;
    private double desvio_estandar=0;
    private double datos[];

    private void CalcularEsperanza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=this.datos[cont];
        }
        
        this.esperanza=aux/(double)(this.datos.length);
    }

    private void CalcularVarianza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=Math.pow(this.datos[cont]-this.esperanza, 2);
        }
        
        this.varianza=aux/(double)(this.datos.length);
    }
    
    private void CalcularDesvioEstandar()
    {
        this.desvio_estandar=Math.sqrt(this.varianza);
    }

    public Esperanza(double datos_a_utilizar[]) //Constructor
    {
        if(datos_a_utilizar==null)
            return;        
        
        this.datos=datos_a_utilizar;
        this.CalcularEsperanza();
        this.CalcularVarianza();
        this.CalcularDesvioEstandar();
    }
}

El constructor requiere que se pasen los datos por argumento, verifica que el haya datos preguntando si es "null" y asigna los datos a la variable de la clase para luego realizar los cálculos mediante la llamada a los métodos. Vean que el contructor es del tipo publico, para que pueda ser accedido desde el exterior.

Por último para obtener los datos calculados desde el exterior, se puede implementar el uso de métodos que devuelvan las variables de la clase, será importante que estos métodos sean públicos:

PHP:
package Estadistica;

public class Esperanza {
    private double esperanza=0;
    private double varianza=0;
    private double desvio_estandar=0;
    private double datos[];

    private void CalcularEsperanza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=this.datos[cont];
        }
        
        this.esperanza=aux/(double)(this.datos.length);
    }

    private void CalcularVarianza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.length; cont++)
        {
            aux+=Math.pow(this.datos[cont]-this.esperanza, 2);
        }
        
        this.varianza=aux/(double)(this.datos.length);
    }
    
    private void CalcularDesvioEstandar()
    {
        this.desvio_estandar=Math.sqrt(this.varianza);
    }

    public Esperanza(double datos_a_utilizar[]) //Constructor
    {
        if(datos_a_utilizar==null)
            return;        
        
        this.datos=datos_a_utilizar;
        this.CalcularEsperanza();
        this.CalcularVarianza();
        this.CalcularDesvioEstandar();
    }

    //------------- Métodos de devolución ---------------------//
    public double GetEsperanza()
    {
        return this.esperanza;
    }
    
    public double GetVarianza()
    {
        return this.varianza;
    }
    
    public double GetDesvioEstandar()
    {
        return this.desvio_estandar;
    }
    //------------- Métodos de devolución ---------------------//    
}

Como verán los métodos son bien sencillos.

Hasta acá tenemos la clase "Esperanza" lista, ahora hay que usarla mediante un objeto desde el main principal del proyecto en la clase "EjemploConsolaDos":

PHP:
package ejemploconsolados;

import Estadistica.Esperanza;

public class EjemploConsolaDos {

    public static void main(String[] args) {
        double datos[]={1,2,3,4,5};
        Esperanza calculo_estadistico=new Esperanza(datos);
        
        System.out.println("Esperanza: "+calculo_estadistico.GetEsperanza());
        System.out.println("Varianza: "+calculo_estadistico.GetVarianza());
        System.out.println("Desvio: "+calculo_estadistico.GetDesvioEstandar());
    }
    
}

Se puede ver que al crear el objeto "calculo_estadistico", cuando se asigna "new Esperanza(datos);", en realidad se está llamando al constructor.

Luego para llamar a los métodos públicos creados en la clase, solo hace falta mencionar el objeto seguido de un "." y elegir el método.

El resultado durante la ejecución es:

Código:
run:
Esperanza: 3.0
Varianza: 2.0
Desvio: 1.4142135623730951
BUILD SUCCESSFUL (total time: 0 seconds)

Si se intentará llamar a una variable de la clase "Esperanza" desde el objeto "calculo_estadistico", veríamos que no tendríamos acceso:

Acceso.PNG

Si en la clase "Esperanza", hiciéramos pública la variable "varianza", veríamos esto:

Acceso2.PNG
 
Para terminar con la programación en consola (lo básico para empezar), agregaría el uso del try/catch y las listas.

Try/Catch:

Sirven para evitar errores de excepción, por ej. si queremos convertir un string en un valor entero y el ingreso nada tiene que ver, se puede producir un error de excepción.

Supongamos este código:

PHP:
public class Prueba {

    public static void main(String[] args) {
        int dato_entrada=0;
        Scanner entradaEscaner = new Scanner (System.in); 
        String ingreso= entradaEscaner.nextLine();
        
        dato_entrada=Integer.parseInt(ingreso);
        
        System.out.println("Valor de entrada: "+dato_entrada);
    }
    
}

Creamos un Scanner para leer el teclado y mediante el método "parseInt" de la clase "Integer", convertimos el valor de ingreso que se encuentra en una variable de tipo String en una variable de tipo int, es como la función "atoi" (array to int) en C.

Si ingresamos un valor, el resultado será el siguiente:

Código:
run:
1
Valor de entrada: 1
BUILD SUCCESSFUL (total time: 1 second)

Sin embargo, si mi ingreso no fuera un número, este sería el resultado:

Código:
run:
prueba
Exception in thread "main" java.lang.NumberFormatException: For input string: "prueba"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at ejemploconsolados.Prueba.main(Prueba.java:27)
Java Result: 1
BUILD SUCCESSFUL (total time: 4 seconds)

En otras palabras, no le gustó ni un poco.

Para evitar este problema, se utiliza el try/catch:

PHP:
public class Prueba {

    public static void main(String[] args) {
        int dato_entrada=0;
        Scanner entradaEscaner = new Scanner (System.in); 
        String ingreso= entradaEscaner.nextLine();
        
        try
        {
            dato_entrada=Integer.parseInt(ingreso);
        }
        catch(Exception e)
        {
            System.out.println("Error de ingreso!.\n"+e.toString());
            return;
        }
        
        System.out.println("Valor de entrada: "+dato_entrada);
    }
    
}

Si mi ingreso es un valor númerico válido, el try seguirá su curso, de lo contrario, entrará en el catch, informando del error:

Código:
run:
g
Error de ingreso!.
java.lang.NumberFormatException: For input string: "g"
BUILD SUCCESSFUL (total time: 7 seconds)

De esta forma se evitó un error de excepción, se informó del error e incluso se redirigió el código (en este caso con el uso del return).

Esta herramienta es muy útil para ingresos de datos, posibles errores en el uso de alguna interfaz de comunicación (puerto serie, ethernet, etc) o incluso en archivos.

Listas:

Volviendo al ejemplo anterior "EjemploConsolaDos", una alternativa de usar un array para los datos, puede ser el uso de listas. La ventaja principal que nos brinda es trabajar con una lista de datos de tamaño dinámico, es decir se pueden ir agregando datos a medida que se realiza por ej. un ingreso. Si bien con el uso de arrays se puede implementar tranquilamente un algoritmo de array dinámico, implica trabajarlo un poco (crear un array de un elemento mayor, copiar el contenido, etc), con las listas, si bien debe realizar algo similar, nos olvidamos de todo eso.

Modificando la clase "Esperanza" de la siguiente forma:

PHP:
package Estadistica;

import java.util.ArrayList;

public class Esperanza {
    private double esperanza=0;
    public double varianza=0;
    private double desvio_estandar=0;
    ArrayList datos;
    
    private void CalcularEsperanza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.size(); cont++)
        {
            aux+=(double)(this.datos.get(cont));
        }
        
        this.esperanza=aux/(double)(this.datos.size());
    }
    
    private void CalcularVarianza()
    {
        double aux=0;
        
        for(int cont=0; cont<this.datos.size(); cont++)
        {
            aux+=Math.pow((double)(this.datos.get(cont))-this.esperanza, 2);
        }
        
        this.varianza=aux/(double)(this.datos.size());
    }
    
    private void CalcularDesvioEstandar()
    {
        this.desvio_estandar=Math.sqrt(this.varianza);
    }
    
    public Esperanza(ArrayList datos_a_utilizar) //Constructor
    {
        if(datos_a_utilizar.isEmpty())
            return;        
        
        this.datos=datos_a_utilizar;
        this.CalcularEsperanza();
        this.CalcularVarianza();
        this.CalcularDesvioEstandar();
    }
    
    //------------- Métodos de devolución ---------------------//
    public double GetEsperanza()
    {
        return this.esperanza;
    }
    
    public double GetVarianza()
    {
        return this.varianza;
    }
    
    public double GetDesvioEstandar()
    {
        return this.desvio_estandar;
    }
    //------------- Métodos de devolución ---------------------//
}

Modificaciones:

- Se agregó el paquete "import java.util.ArrayList".
- El vector de tipo double, pasó a ser una variable del tipo "ArrayList".
- El manejo de una lista requiere el uso de sus métodos:
. size(): tamaño de la lista.
. isEmpty(): devuelve un true/false según si se encuentra vacía o no.
. get(indice): devuelve el elemento según el indice, el elemento es necesario castearlo a una variable del tipo "double".

Si en la clase "EjemploConsolaDos", agregamos las modificaciones y el ingreso usando el try/catch:

PHP:
package ejemploconsolados;

import Estadistica.Esperanza;
import java.util.ArrayList;
import java.util.Scanner;

public class EjemploConsolaDos {

    public static void main(String[] args) {
        ArrayList datos = new ArrayList<Double>();
        int cant_datos;
        Scanner entradaEscaner = new Scanner (System.in); 
        
        System.out.println("Ingrese la cantidad de datos que tendrá la lista:");
        
        String ingreso= entradaEscaner.nextLine();
        
        try
        {
            cant_datos=Integer.parseInt(ingreso);
        }
        catch(Exception e)
        {
            System.out.println("Ingreso de un dato incorrecto.");
            return;
        }
        
        System.out.println("Ingrese los datos:");
        for(int cont=0; cont<cant_datos; cont++)
        {
            ingreso= entradaEscaner.nextLine();
            
            try
            {
                datos.add(Double.parseDouble(ingreso));            
            }
            catch(Exception e)
            {
                System.out.println("Ingreso de un dato incorrecto.");
                return;
            }
        }
        
        Esperanza calculo_estadistico=new Esperanza(datos);
        
        System.out.println("Esperanza: "+calculo_estadistico.GetEsperanza());
        System.out.println("Varianza: "+calculo_estadistico.GetVarianza());
        System.out.println("Desvío: "+calculo_estadistico.GetDesvioEstandar());       
    }
    
}

Modificaciones:

- El array de datos pasa a ser "ArrayList datos" de tipo double.
- Se ingresa la cantidad de datos que tendrá la lista.
- Se ingresan los datos y mediante el método "add()" de la clase ArrayList, se agregan los datos en la lista.

Como resultado:

Código:
run:
Ingrese la cantidad de datos que tendrá la lista:
5
Ingrese los datos:
1
2
3
4
5
Esperanza: 3.0
Varianza: 2.0
Desvío: 1.4142135623730951
BUILD SUCCESSFUL (total time: 8 seconds)
 
Última edición:
Sin ir demasiado a los detalles, una clase nos permite definir variables y métodos (método=funciones) en un cierto bloque de código, en cambio un objeto es la implementación de esa clase en forma de "variable", en otras palabras la clase es la que permite definir la característica de un objeto.
Esto es un tema que si bien es super-básico es primordial que se entienda claramente que corno es una clase y que es un objeto. He tenido alumnos que nunca entendieron las diferencias entre una y otra cosa hasta que se les explica con un ejemplo de algo tangible y fácilmente accesible. Por supuesto, si no saben que es una clase, nunca van a poder programar orientado a objetos... y ni hablemos de intentar diseñar algo medianamente coherente.

Para hacerla corta y rápido, hay que tener en mente la imagen de la mamá en la cocina preparando un bizcochuelo (una torta).
La clase es el MOLDE de la torta, que puede ser redondo. cuadrado, con forma de estrella o con un agujero al medio, pero tener el molde NO SIGNIFICA que tengamos una torta, así que hay que meterle adentro la masa (que puede ser de vainilla, de naranja, de chocolate, etc). Una vez que ponemos la masa y la cocinamos, al rato tenemos listo el bizcochuelo con la forma del molde, que luego hay que adornar, bañar en merengue o lo que se les ocurra.
Si esta explicación les quedó clara, es fácil entender que que una clase es un molde para construir objetos, y que los objetos no son mas que las tortas creadas usando esos moldes. Como cada molde puede ser de diferente forma, tendremos tortas diferentes de acuerdo a la forma del molde que usemos para construirla. Entonces, cuando la teoría dice que un objeto es una instancia de una clase (muy académico pero no se entiende un pomo) lo que está diciendo es que un objeto es una "entidad" que se ha construido usando una plantilla que le dá la "forma", y esa plantilla es una clase...

Otra cosa importante es que si pretenden usar POO para hacer los mismos desastres que se hacen en programación estructurada convencional, pues les aviso que mejor no gasten tiempo en esto por que no van a llegar a ninguna parte. La POO requiere técnicas de modelado (cosa que nunca nadie quiere hacer) mas o menos avanzadas, y se usa un lenguaje de modelado llamado UML, y requiere conocer las soluciones que otros ya han inventado y que han probado ser eficientes y controlables. Acá no hay que inventar la rueda para decir "que genio que soy" mientras se miran el ombligo, por que hay un 99% de probabilidad de que la solución a su problema ya se haya inventado hace 20 o más años. Para esto hay que estudiar y aprender unas cosas que se llaman Patrones de Diseño, y que reunen toda la sabiduría en análisis y diseño OO de los ultimos 30 años. Si no van a ir por este lado, y en especial aplicando JAVA... están perdiendo el tiempo.

Cosme les está explicando las cosas básicas del lenguaje como para que no arranquen desde cero en el lenguaje, pero un mono con un lápiz y tiempo suficiente también puede aprender el lenguaje, así que supongo que querrán ser superiores al simio... :cool:
 
Código:
Hasta ahora los ejemplos fueron en consola, la idea es empezar con algo básico en Swing (las librerías gráficas de Java) para hacer una ventana con entrada de datos y que realice alguna acción.

Primero vamos a crear el proyecto "EjemploSwingUno":

1- Archivo -> Nuevo Proyecto
2- Java -> Aplicación Java -> Siguiente
3- Nombre del proyecto -> EjemploSwingUno

Con el proyecto creado, agregamos un paquete llamado "Ventanas", por último haciendo click derecho sobre el paquete seleccionamos "New (nuevo)" -> "JFrame (Form)" y lo llamamos "Principal". Como resultado de esto, nuestro proyecto debería quedar así:

Proyecto-1.PNG

A la izquierda se pueden ver los archivos que posee el proyecto y a la derecha se observa el editor gráfico del Netbeans (esta es la magia del IDE), en otras palabras vamos a poder editar en forma gráfica el aspecto de la ventana "Principal". La diferencia entre un JFrame y un Jdialog, es que el frame será la ventana principal de todo programa (solo debe haber uno) y los diálogos serán llamados desde ese frame único, que tomarán al Jframe como argumento a la hora de ser llamados.

Como primera medida vamos hacer que el programa al ejecutarse muestre la ventana, para hacer eso agregamos las siguientes líneas en el main que se encuentra en el archivo "EjemploSwingUno.java", recuerden el programa inicia desde ahí:

PHP:
package ejemploswinguno;

import Ventanas.Principal;

public class EjemploSwingUno {
    
    public static void main(String[] args) {
        Principal ventana=new Principal();
        
        ventana.setVisible(true);
    }
    
}

En el main se:

- Importó la clase Principal.
- Creó un objeto de la clase Principal llamado ventana.
- Llamó al método "setVisible" para hacer visible la ventana, con ese método también se puede ocultar una ventana.

Al ejecutar, vamos a ver que se abre una ventana arriba en el margen izquierdo que no tiene contenido.

Ahora vamos a investigar un poco el código de la ventana, para eso vamos a "Principal.java" y presionamos sobre el botón "source" para ver el código, vamos a ver una cosa así:

PHP:
package Ventanas;

public class Principal extends javax.swing.JFrame {

    public Principal() {
        initComponents();
    }

    private void initComponents() {
       ....
    }                        

    public static void main(String args[]) {
      ....
    }             
}

Nos encontramos con tres métodos:

- main => NO SE TOCA (el editor gráfico se encarga de modificarlo).
- initComponents => NO SE TOCA (el editor gráfico se encarga de modificarlo a medida que agregamos controles gráficos).
- Principal => es el constructor y por donde inicia nuestra ventana desde el main "EjemploSwingUno.java" cuando creamos el objeto "ventana".

Ya tenemos la ventana, lo primero que vamos hacer es centrarla en pantalla, para hacer eso debemos averiguar la resolución de pantalla que tiene el equipo usando las siguientes líneas:

PHP:
private final int ancho_pantalla = java.awt.Toolkit.getDefaultToolkit().getScreenSize().width;
private final int alto_pantalla  = java.awt.Toolkit.getDefaultToolkit().getScreenSize().height;

Que las variables sean del tipo final, sirve para indicar que esas variables no serán modificables. Con la resolución en pantalla, ya podemos centrar la ventana usando un poco de matemáticas en el constructor :)confused:):

PHP:
package Ventanas;

public class Principal extends javax.swing.JFrame {
   
    private final int ancho_pantalla = java.awt.Toolkit.getDefaultToolkit().getScreenSize().width;
private final int alto_pantalla  = java.awt.Toolkit.getDefaultToolkit().getScreenSize().height;   

    public Principal() {
        initComponents();

        this.setLocation((ancho_pantalla-this.getWidth())/2,(alto_pantalla-this.getHeight())/2); // Acomodo la ventana en la mitad de la pantalla                
    }

    private void initComponents() {
       ....
    }                        

    public static void main(String args[]) {
      ....
    }             
}

Si vemos el código:

- "this" hace referencia al propio objeto, es decir ventana.
- "setLocation(x, y)" es un método para fijar la posición de la ventana.
- "getWidth()" es un método para obtener el ancho de la ventana.
- "getHeight()" es un método para obtener la altura de la ventana.

Con esto, conseguimos que la ventana inicie en el medio de la pantalla.

Ahora agreguemos un botón que nos permita salir de la ventana (además del uso de la x), para lo cual volvemos a modo de diseño (design) y elegimos el control "button" en la zona de "Palette":

AgregarBotón.jpg

Una vez elegido el botón, lo ubicamos en cualquier lugar de la ventana, por ej. abajo a la derecha. Si hacemos un click izquierdo sobre el botón y a la derecha del IDE nos aparecerán ls propiedades de ese botón (como alternativa se puede presionar botón derecho sobre el botón y elegir propiedades).

De las propiedades del botón vamos a modificar:

- text => Salir (el texto dentro del botón).
- mnemonic => S (sirve para agregar un acceso directo con el teclado, es decir ALT+S).

Luego tenemos otra viñeta que se llama "events" (eventos), que nos servirá para crear uno o varios métodos cuando suceda "algo" con ese botón, por ej. cuando se efectúa una acción sobre el mismo "actionPerformed":

Agregar Evento.png

Haciendo click sobre la flecha de abajo, nos agregará "jButton1ActionPerformed" y nos creará un método en la clase "Principal":

PHP:
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
    }

Como verán es bastante simple el asunto, ese método si lo vemos con ojos de programado de uC, será un "especie" de rutina de interrupción cuando se produzca alguna acción sobre el botón. Hasta este punto, no tuvimos que agregar muchos conocimientos a nuestro limitado JAVA para trabajar con botones, todo lo hizo el editor gráfico del Netbeans.

Con el método agregado, vamos a cerrar la ventana usando el método "dispose" que sirve para "destruir" (literalmente) el objeto ventana, quedando la clase "Principal" de esta forma:

PHP:
package Ventanas;

public class Principal extends javax.swing.JFrame {

    private final int ancho_pantalla = java.awt.Toolkit.getDefaultToolkit().getScreenSize().width;
private final int alto_pantalla  = java.awt.Toolkit.getDefaultToolkit().getScreenSize().height; 

    public Principal() {
        initComponents();

        this.setLocation((ancho_pantalla-this.getWidth())/2,(alto_pantalla-this.getHeight())/2); // Acomodo la ventana en la mitad de la pantalla                
    }
    
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        this.dispose();
    }   

    private void initComponents() {
       ....
    }                        

    public static void main(String args[]) {
      ....
    }             
}

En este punto, si se presiona sobre el botón salir, la ventana se cerrará. Para darle un poco más de orden al código a futuro, sería bueno que en vez de llamarse el botón de salir "jButton1", se llame "BotonSalir", para identificarlo más rápidamente. Esta modificación la podemos hacer desde el editor gráfico, en las propiedades del botón veremos la viñeta "Code", en "variable name" podremos modificar su nombre y el IDE automáticamente renombrará la variable en el código (si... automágico :D). Ahora el método de "actionPerformed" se verá así:

PHP:
    private void BotonSalirActionPerformed(java.awt.event.ActionEvent evt) {                                           
        this.dispose();
    }

Otra característica importante del botón, se encuentra en el tipo de variables, si privada o pública, lo ideal es que se mantenga privada y si es necesario acceder a ella desde afuera que se lo haga mediante un método como vimos en los mensajes anteriores.

Por último a ese botón, sería bueno agregar una pregunta de si realmente se desea salir o no, esto lo podemos hacer agregando una ventana de diálogos mediante el editor gráfico o más sencillo (y es lo que vamos hacer) usar los cuadros de diálogos por default que tiene java:

PHP:
    private void BotonSalirActionPerformed(java.awt.event.ActionEvent evt) {                                           
        int confirmado = JOptionPane.showConfirmDialog(this,"¿Confirma que desea salir?");
        
        if(JOptionPane.OK_OPTION == confirmado)
            this.dispose();
    }

El editor nos pedirá que importemos ciertas librerías (javax.swing.JOptionPane). Si vemos el código, simplemente tenemos que pasar por argumento el Frame principal ("this") y el mensaje que aparecerá en el cuadro, como resultado devolverá un "int" según nuestro accionar, si ese "int" es igual a "JOptionPane.OK_OPTION", significa que presionamos sobre el botón "Si". Si ejecutamos, veremos el siguiente cuadro de diálogos al presionar sobre el botón Salir:

Pregunta al salir.PNG

Bueno, hasta acá se consiguió algo bien básico:

- Crear un Frame y centrarlo.
- Agregar un botón de salida.
- Agregar eventos sobre el botón de salida.
- Agregar un cuadro de diálogo que confirme la salida.

En el próximo mensaje veremos como ingresar datos en la ventana.
 
Última edición:
Siguiendo con el ejemplo, vamos a intentar realizar un programa que lea dos números, los sume y los muestre en pantalla.

Para permitir el ingreso de datos en la "paleta" de control tenemos dos elementos útiles:

- Label: como el nombre lo dice, permite agregar una etiqueta con un String en la ventana, para indicar algo, en este caso, el campo a llenar por el usuario.

- TextField: permite que el usuario ingrese un String, también se puede utilizar para informar informar sobre un cierto resultado.

Volviendo a nuestra ventana, agregaremos 3 labels, 3 textfields de esta forma y achicaremos el tamaño de la ventana, quedando de esta forma:

Labels y TextFields.png

A c/label se le modificará el texto (de forma similar a lo que se hizo con el botón de salir):

- Dato 1:
- Dato 2:
- Resultado:

Luego a los textfield, se le quitarán los textos iniciales por default que tienen colocándoles un "0", se los configurará para que el texto empiece sobre el margen derecho (HorizontalAlignment -> Right), en el caso del último textfield se le quitará la tilde de "editable" (evita que el usuario pueda ingresar un string) y para finalizar, como recomendé en el mensaje anterior, a c/textfield se le renombrará la variable para un fácil reconocimiento (TextoDato1, TextoDato2 y TextoResultado). La ventana finalmente ser verá de esta manera:

Ventana Terminada.PNG

Antes de continuar con la ventana, como se hizo en el mensaje de ingreso de consola, si se van a sumar los datos 1 y 2, previamente vamos a necesitar verificar que el usuario realmente ingresó un valor númerico, de lo contrario vamos a tener problemas. En este punto, c/u puede hacerlo de la manera que mejor le parezca, como en la matemática, a las soluciones se pueden llegar de varias formas; yo lo que propongo es crear una nueva clase que contenga los métodos necesarios para verificar un ingreso de tal forma que la clase se pueda reutilizar a futuro fácilmente.

Entonces, en la zona de proyecto, agregaremos un nuevo paquete llamado "Utiles", luego en el paquete crearemos una nueva clase (java class) llamada "VerificarIngreso", en la nueva clase agregaremos las siguientes líneas de código:

PHP:
package Utiles;

public class VerificarIngreso {
    private int valor_entero=0;
    
    public boolean ValorInt(String dato)
    {
        try
        {
            this.valor_entero=Integer.parseInt(dato);
            return true;
        }
        catch(Exception e)
        {
            this.valor_entero=0;
            return false;
        }
    }
    
    public int GetValorInt()
    {
        return this.valor_entero;
    }
}

Se usan dos métodos:

- ValorInt(String ..): devuelve un valor bolaneo, en caso de que la conversión fuera exitosa devolverá "true", de lo contrario un "false".

- GetValorInt(): permite obtener el valor de la conversión.

La clase es sencilla y corta, pero podrá ser expandida a futuro por otro tipo verificaciones, como por ej. variables del tipo double o incluso enteros en un rango acotado:

PHP:
package Utiles;

public class VerificarIngreso {
    private int valor_entero=0;
    
    public boolean ValorInt(String dato)
    {
        try
        {
            this.valor_entero=Integer.parseInt(dato);
            return true;
        }
        catch(Exception e)
        {
            this.valor_entero=0;
            return false;
        }
    }
    
    public boolean ValorInt(String dato, int valor_min, int valor_max)
    {
        try
        {
            int entero_aux=Integer.parseInt(dato);
            
            if((entero_aux>=valor_min)&&(entero_aux<=valor_max))
            {
                this.valor_entero=entero_aux;
                return true;
            }
            else
            {
                this.valor_entero=valor_min;
                return false;
            }
            
        }
        catch(Exception e)
        {
            this.valor_entero=valor_min;
            return false;
        }
    }
    
    public int GetValorInt()
    {
        return this.valor_entero;
    }
}

Entonces como verán, la idea es siempre hacer bloques simples para luego juntarlos y hacer algo más complejo.

Volviendo a la ventana, vamos agregar un evento en el textfield para saber cuando el usuario haya ingresado un dato, para lo cual vamos a utilizar el evento "FocusLost" que permite saber cuando el usuario quita el cursor del textfield, de esa forma podremos ver si hay un cambio en el texto y de paso utilizaremos los métodos de verificación de la clase anterior. En la rutina haremos lo siguiente:

PHP:
     private void TextoDato1FocusLost(java.awt.event.FocusEvent evt) {                                     
        // TODO add your handling code here:
        VerificarIngreso ver_int= new VerificarIngreso();
        String dato_ingresado_1=this.TextoDato1.getText();
        String dato_ingresado_2=this.TextoDato2.getText();
        
        if(ver_int.ValorInt(dato_ingresado_1))
        {
            int dato1=ver_int.GetValorInt();
            ver_int.ValorInt(dato_ingresado_2);
            int dato2=ver_int.GetValorInt();
            
            int resultado=dato1+dato2;
            
            this.TextoResultado.setText(String.valueOf(resultado));
        }
        else
        {
            JOptionPane.showMessageDialog(this, "El valor ingresado no es válido.");
            this.TextoDato1.setText("0");
        }
    }

- Creamos un objeto del tipo VerificarIngreso.
- Leemos los string ingresados en los textfield utilizado el método "getText()" que poseen los textfields.
- Usamos el método de verificación de enteros que realizamos previamente.
- En caso de verificar, obtenemos el valor entero ingresado en el TextoDato1, repetimos el procedimiento con el TextoDato2 (no es necesario verificar en esta caso, el dato ya se encontraba ingresado previamente), sumamos los dos enteros y mostramos el resultado en TextoResultado mediante el uso del método "setText()" previamente convertido el entero en string.
- En caso de no verificar, llenamos el TextoDato1 con un "0" e informamos del error de ingreso mediante el uso de un JOptionPane.

La cantidad de variables claramente se podrían reducir, pero preferí que el código quede bien entendible. Repetimos la rutina pero con el TextoDato2, es decir agregamos un evento de "FocusLost":

PHP:
     private void TextoDato1FocusLost(java.awt.event.FocusEvent evt) {                                     
        // TODO add your handling code here:
        VerificarIngreso ver_int= new VerificarIngreso();
        String dato_ingresado_1=this.TextoDato1.getText();
        String dato_ingresado_2=this.TextoDato2.getText();
        
        if(ver_int.ValorInt(dato_ingresado_2))
        {
            int dato2=ver_int.GetValorInt();
            ver_int.ValorInt(dato_ingresado_1);
            int dato1=ver_int.GetValorInt();
            
            int resultado=dato1+dato2;
            
            this.TextoResultado.setText(String.valueOf(resultado));
        }
        else
        {
            JOptionPane.showMessageDialog(this, "El valor ingresado no es válido.");
            this.TextoDato2.setText("0");
        }
    }

Eso es todo, ya tienen su primer "sumador" gráfico en Java con verificación y todo.

Resultado.PNG

Código de la ventana:

PHP:
package Ventanas;

import Utiles.VerificarIngreso;
import javax.swing.JOptionPane;

public class Principal extends javax.swing.JFrame {
    
    private final int ancho_pantalla = java.awt.Toolkit.getDefaultToolkit().getScreenSize().width;
    private final int alto_pantalla  = java.awt.Toolkit.getDefaultToolkit().getScreenSize().height;
    
    public Principal() {
        initComponents();
        
        this.setLocation((ancho_pantalla-this.getWidth())/2,(alto_pantalla-this.getHeight())/2); // Acomodo la ventana de presentación en la mitad de la pantalla        
        
    }

    private void initComponents() {
          .... //Mucho código que no nos interesa! 
    }                        

    private void BotonSalirActionPerformed(java.awt.event.ActionEvent evt) {                                           
        int confirmado = JOptionPane.showConfirmDialog(this,"¿Confirma que desea salir?");
        
        if(JOptionPane.OK_OPTION == confirmado)
            this.dispose();
    }                                          

    private void TextoDato1FocusLost(java.awt.event.FocusEvent evt) {                                     
        // TODO add your handling code here:
        VerificarIngreso ver_int= new VerificarIngreso();
        String dato_ingresado_1=this.TextoDato1.getText();
        String dato_ingresado_2=this.TextoDato2.getText();
        
        if(ver_int.ValorInt(dato_ingresado_1))
        {
            int dato1=ver_int.GetValorInt();
            ver_int.ValorInt(dato_ingresado_2);
            int dato2=ver_int.GetValorInt();
            
            int resultado=dato1+dato2;
            
            this.TextoResultado.setText(String.valueOf(resultado));
        }
        else
        {
            JOptionPane.showMessageDialog(this, "El valor ingresado no es válido.");
            this.TextoDato1.setText("0");
        }
    }                                    

    private void TextoDato2FocusLost(java.awt.event.FocusEvent evt) {                                     
        // TODO add your handling code here:
        VerificarIngreso ver_int= new VerificarIngreso();
        String dato_ingresado_1=this.TextoDato1.getText();
        String dato_ingresado_2=this.TextoDato2.getText();
        
        if(ver_int.ValorInt(dato_ingresado_2))
        {
            int dato2=ver_int.GetValorInt();
            ver_int.ValorInt(dato_ingresado_1);
            int dato1=ver_int.GetValorInt();
            
            int resultado=dato1+dato2;
            
            this.TextoResultado.setText(String.valueOf(resultado));
        }
        else
        {
            JOptionPane.showMessageDialog(this, "El valor ingresado no es válido.");
            this.TextoDato2.setText("0");
        }
    }                                    

    public static void main(String args[]) {
        .... //Más código que no nos interesa! 
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton BotonSalir;
    private javax.swing.JTextField TextoDato1;
    private javax.swing.JTextField TextoDato2;
    private javax.swing.JTextField TextoResultado;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    // End of variables declaration                   
}

Como verán el uso de las librerías gráficas no es tan complejo como parece, de hecho es el propio Netbeans el que se encarga de resolver la mayoría de las cosas. Después pueden jugar con los eventos y ver si lo pueden mejorar, pero la idea siempre será la misma.
 
Profe, ¿tenés algún buen tutorial de como integrar Java con C++?

Yo conseguí implementar una función nativa en C, usando javah y montonazo de cosas que termina siendo muy engorroso. En visual studio, juntar C# con C++ es bastante sencillo usando librerías dinámicas.
 
Yo use el tutorial de java.sun.com (que ahora te manda a Oracle) pero es bastante simple.
1- Declaras la clase con metodos nativos (que deberian estar en una capa "inferior" a la interfaz de clase... pero esto puede discutirse).
2- Ejecutas el javah para generar los protipos de los metodos nativos en C.
3- Con los protipos tenes como definir las funciones, asi que las programas en C o C++ (yo las escribo en C nomas).
4- Compilas y generas una dll.
5- Le agregas a la clase un bloque estatico con un System.loadLibrary(elnombredeladll);
6-Corres el programa y listo.

Dependiendo de la cancha que logres tendras que repetir los pasos 3 y 4 hasta que funcione. Si le pifiaste mal tendras que repetir desde el paso 1.

Y no hay mucho mas...
Con eso he autenticado cosas contra un Active Directory, he usado memoria compartida con programas en C generados por el RT de Matlab, he hablado con drivers de Windows y algunas otras menudencias...
 
Última edición:
Ok, eso es lo que había hecho, pensé que tal vez había un método más rápido y menos engorroso.
Y que parte te resulta engorrosa?? Lo unico diferente de un proceso de desarrollo normal es el uso del javah, que podés "automatizar" con un .bat o un script de ANT o lo que quieras.
Lo demás es escribir código y compilar... como siempre...
C# es más fácil por que el run-time está integrado al sistema operativo, pero en Java tenés que hablar con la JVM que es independiente del S.O.
 
Lo que no pude hasta ahora es debuggear dentro de la función nativa, siempre me lleva al "cargador" de la librería, pero nunca lo llama.
Para no pelear con cosas "raras", yo siempre pruebo las funciones en C dentro de un programa en C a tal efecto. Cuando ya están probadamente OK, las incluyo como métodos nativos... total, solo hay que ajustar los tipos de datos involucrados y nada mas.
 
Para no pelear con cosas "raras", yo siempre pruebo las funciones en C dentro de un programa en C a tal efecto. Cuando ya están probadamente OK, las incluyo como métodos nativos... total, solo hay que ajustar los tipos de datos involucrados y nada mas.
Si, supongo que no queda otra, tampoco es tan terrible, pero hay veces que puede ser útil.

De hecho, la idea de usar c++ o c, es para poder usar el opencv para procesar imágenes e integrarlo a java mediante el opengl.

Algo así hago con c# (interfaz de usuario) y c++ (procesamiento, más que nada, refresco de pantalla o ventana).

La idea es encontrar una combinación similar en Linux. De alguna manera quiero usar los conocimientos que tengo de java para realizar una interfaz de usuario sencilla (con java eso es muy fácil), pero que el procesamiento si lo haga en c porque java apesta con el tipo de variables que tiene para imágenes.

Y la verdad no quiero ir a otra alternativa de interfaz de usuario como gtk o qt.
 
Última edición:
Solia haber una biblioteca de imagenes para Java, que decian que era muy buena. Yo no la probe nunca, y dudo que alcance a OpenCV, pero bue... habria que probarla si es que aun existe.
Por otro lado, por buenos que sean los tipos que usa opencv, el acceso desde Java vas a tener que hacerlo por medio de sus tipos.
 
Atrás
Arriba