Hola.
Mira, para publicar código aquí en el foro, has de ponerlo entre las etiquetas
codeEstas etiquetas aparecen automáticamente en el texto de los botones de arriba del campo de texto, si pulsas el botón con esta imagen -->
Yo a veces, cuando quiero resaltar texto en colores para poder explicarme mejor, uso como alternativa las etiquetas
quote, que es el botón con la imagen -->
No es lo ideal para compartir código, pero sí para dar explicaciones.
Sobre tu código, hay algunos fallos totalmente comprensibles si no se conoce bien el lenguaje Java.
El array te sale con valor nulo porque NUNCA se inicia con unos valores. Tu crees que sí, pero no es así.
El array que señalo en azul, en realidad, es otro array distinto del que señalo en rojo:
public class Filtro {
private static Salud[] arrayFiltro;
public static void main(String[] args) {
Salud[] arrayRecords = new Salud[]{
new Salud("Sangre", "Colesterol"),
new Salud("Termometro", "Temperatura"),
new Salud("Oximetro", "Oxigeno"),
new Salud("Tensiometro", "Presion Arterial"),
new Salud("Glucosa", "Azucar en la Sangre"),
};
Salud[] arrayFiltro = new Salud[]{
new Salud("Gasa", "Suturas"),
new Salud("Tensiometro", "Alcohol")
};
Aunque se llamen igual, son arrays diferentes.
¿Por qué? Porque en el array que señalo en rojo, delante del nombre has puesto Salud[]
Salud[] arrayFiltro = new Salud[]
Al hacerlo así, Java interpreta que estás declarando un array totalmente nuevo, a pesar de que tiene el mismo nombre que el que hay señalado en azul. Y en esta ocasión te permite usar el mismo nombre para dos arrays, porque están en
distintos ámbitos(lo de los ámbitos no lo vamos a explicar ahora porque será demasiada info de golpe...)
La cuestión es que para que Java sepa que en realidad lo que quieres inicializar es el array declarado previamente, para inicializarlo has de poner solamente su nombre, sin indicar su tipo de dato.
public class Filtro {
private static Salud[] arrayFiltro;
public static void main(String[] args) {
Salud[] arrayRecords = new Salud[]{
new Salud("Sangre", "Colesterol"),
new Salud("Termometro", "Temperatura"),
new Salud("Oximetro", "Oxigeno"),
new Salud("Tensiometro", "Presion Arterial"),
new Salud("Glucosa", "Azucar en la Sangre"),
};
arrayFiltro = new Salud[]{
new Salud("Gasa", "Suturas"),
new Salud("Tensiometro", "Alcohol")
};
Aquí ahora, sí estamos tratando con el mismo array, y no con dos.
Sobre el método filtrados(), aquí hay mucho que comentar...
Comencemos por la comparación que señalo en rojo.
public static ArrayList<Salud> filtrados(Salud[] arrayRecords) {
ArrayList<Salud> objetosFiltrados = new ArrayList<>();
for(int i=0; i<arrayRecords.length; i++) {
if(arrayRecords[ i] == arrayFiltro[ i] || arrayRecords[ i].item == arrayFiltro[ i].item || arrayRecords[ i].item == arrayFiltro[ i].item2 || arrayRecords[ i].item2 == arrayFiltro[ i].item)
objetosFiltrados.add(arrayFiltro[ i]);
}
return objetosFiltrados;
}
Ahí estás preguntando (bueno,
pretendes preguntar...) si dos elementos de clase
Salud son iguales
El comparador
== solo sirve para comparar
tipos de datos primitivos.
Los tipos int, double, char, float, boolean, byte, short y long son los llamados tipos primitivos.
Se les llama primitivos porque son datos simples, básicamente son valores numéricos y por eso es muy fácil compararlos para saber si son iguales
== , si uno es mayor
> , si es menor
< ...
Para el ordenador es muy fácil determinar si 5 es mayor que 4.
En cambio, el resto de datos que vamos a manejar en Java, serán
objetos de claseString, ArrayList, Scanner, Math,
Salud, Object, Persona, Animal, Estudiante, Vehículo,...
La lista es infinita porque nosotros mismos podemos crear tantas nuevas clases como nos de la imaginación.
Todos estos datos son mucho más complejos internamente y no es fácil hacer comparaciones entre ellos.
Ya no es solo una cuestión de complejidad interna, si no también de la naturaleza de cada clase.
Si comparamos dos objetos Persona para saber si son iguales, no podemos usar simplemente
== y ya está.
Porque, ¿cómo puede saber el computador si son iguales?
¿Por tener mismo nombre y apellidos? Pues no, hay cientos de personas que se llaman Francisco Rodriguez Lopez y no son la misma...
Para comparar objetos de clases, hay que escribir código y decirle al computador cómo queremos que decida si son iguales, o quien es mayor y menor.
Para el ejemplo de objetos Persona, probablemente le pediremos que compare sus DNI / cédula identificativa para determinar si dos personas "son iguales".
Aunque quizás en nuestro programa nos da igual sus nombres e ID, quizás sea un programa para crear dietas saludables y entonces vamos a querer considerar a dos Personas iguales si tienen la misma edad y peso...
Pero bueno, no vamos a profundizar más en esto.
Lo importante es que recuerdes que hay dos tipos de datos:
- los primitivos (se escriben en minúscula) con los que podemos usar los operadores de comparación
- las clases (se escriben con la primera letra mayúscula) que por su complejidad y naturaleza variable se necesita escribir código extra para decidir cómo se comparan
Si para objetos de clase utilizas el comparador
==, Java te lo admite como sintaxis correcta, pero no va a hacer lo que tú necesitas.
Lo que va a hacer es comprobar si esos objetos, en realidad son uno solo pero con distintas
referencias.
Tampoco quiero divagar mucho con esto ahora, pero has de saber que un mismo objeto de clase puede tener muchas referencias (nombres).
Si yo hago esto:
Persona persona1 = new Persona("Perico", "Palotes");
Persona persona2 = persona1;
Persona persona3 = persona2;
Hay tenemos tres referencias: persona1, persona2 y persona3.
Pero en realidad solo hay un objeto, lo que pasa es que esas tres referencias están
apuntando al mismo objeto.Entonces, si preguntamos esto:
if (persona1 == persona3)
La respuesta será TRUE, porque apuntan al mismo objeto.
Ahora, si escribimos esto:
Persona persona1 = new Persona("Perico", "Palotes");
Persona persona2 = persona1;
Persona persona3 = new Persona("Perico", "Palotes");
Y volviéramos a preguntar si persona1 es igual que persona3, la respuesta sería FALSE.
Porque ahora
apuntan a dos objetos distintos. No importa si tienen el mismo nombre y apellido, internamente ocupan distintas posiciones de memoria así que son dos objetos diferentes.
Vale, te he escrito media Biblia para decirte que no puedes usar el comparador
== con la clase
SaludDe hecho, el resto de comparaciones donde comparas los "item" tampoco van a funcionar bien, porque los item son de clase String, así que tampoco nos sirve el comparador
== public static ArrayList<Salud> filtrados(Salud[] arrayRecords) {
ArrayList<Salud> objetosFiltrados = new ArrayList<>();
for(int i=0; i<arrayRecords.length; i++) {
if(arrayRecords[ i] == arrayFiltro[ i] || arrayRecords[ i].item == arrayFiltro[ i].item || arrayRecords[ i].item == arrayFiltro[ i].item2 || arrayRecords[ i].item2 == arrayFiltro[ i].item)
objetosFiltrados.add(arrayFiltro[ i]);
}
return objetosFiltrados;
}
¿Entonces cómo carajo podemos comparar las clases?
Hay varias formas, pero la principal es utilizar
el método equals(). Este es un método especial que TODAS las clases de Java poseen.
Sí, tu clase
Salud también lo tiene aunque tú no se lo hayas escrito. Es un método que todas las clases heredan automáticamente (no voy a explicar ahora herencia de clases), sin embargo, por sí solo no sirve para nada. Los programadores debemos
sobreescribir dicho método para dotarlo de las instrucciones necesarias para que el computador sepa como ha de comparar los objetos de nuestra clase.
Así que nos vamos a tu clase
Salud(que también requiere de otras correcciones que veremos luego) y comenzamos añadiendo lo siguiente:
class Salud {
public final String item;
public final String item2;
private Salud[] arrayRecords;
public Salud(String item, String item2){
this.item = item;
this.item2 = item2;
}
public void display(){
System.out.println("Los record que coinciden son: " + Filtro.filtrados(arrayRecords));
}
public String getItem() {
return this.item;
}
public String getItem2() {
return this.item2;
}
@Override
public boolean equals(Object objeto) {
}
}
Ahí dentro de ese método, vamos a decidir como deben compararse dos objetos Salud para determinar si son iguales.
La etiqueta
@Override no es obligatoria, pero si recomendable. Sirve para decirle a Java que ese método va a sobrescribir un método que se recibe por herencia, así el compilador se encargará de comprobar que lo estamos sobrescribiendo correctamente.
Además también sirve para que otros programadores que lean nuestro código, sepan enseguida que es un método heredado.
Fíjate que el método recibe como argumento un
tipo de dato Object, esta es una clase especial, es la madre de TODAS las clases. De hecho, es de ella de quien las otras clases heredan el método
equals() y otros más.
Esto significa que este método puede recibir un objeto que no sea de clase Salud, cosa que hemos de tener en cuenta a la hora de compararlos
Bien, ahora es cuando hemos de decidir cuándo dos objetos
Salud son iguales.
A priori, lo normal sería considerar dos objetos
Salud iguales, si sus dos items son también iguales.
Sin embargo, para hacer el filtrado nos basta con que al menos uno de sus items coincidan. Así que eso es lo que vamos a decidir:
- Dos objetos
Salud serán iguales si al menos uno de sus items coinciden
@Override
public boolean equals(Object objeto) {
if (objeto instanceof Salud) { //Si objeto recibido es de clase Salud...
//Lo instanciamos como Salud
Salud otroObjeto = (Salud) objeto;
//Si al menos uno de sus items coinciden, se considerarán iguales
if (this.item.equals(otroObjeto.item) || this.item.equals(otroObjeto.item2)
|| this.item2.equals(otroObjeto.item) || this.item2.equals(otroObjeto.item2))
return true;
else
return false; //Ningún item coincide
}
else
return false; //Objeto recibido no es clase Salud
}
Lo primero que hacemos es comprobar si el
Object recibido es en realidad de clase
Salud.
Si no lo es, retornamos FALSE y se acabó.
Si lo es, entonces hacemos un
casting para tratarlo como un objeto
Salud y pasamos a comparar sus items.
Si alguno coincide, retornamos TRUE.
Si no coincide, retornamos FALSE.
Fíjate que para compara los items, también estamos usando un método equals(). Este equals() pertenece a la clase
String.
Así que para comparar cadenas
String usaremos también equals(), la diferencia es que este método ya viene escrito "de fábrica" por el Sr. Java, no hace falta que también lo escribamos nosotros. Los
String ya saben como han de compararse entre ellos.
Vale, pues ya tenemos nuestro método equals(), ¿cómo le damos uso?
Volvemos a la clase
Filtro, al método donde hacíamos las comparaciones.
Ahora basta con comparar de esta manera:
public static ArrayList<Salud> filtrados(Salud[] arrayRecords) {
ArrayList<Salud> objetosFiltrados = new ArrayList<>();
for(int i=0; i<arrayRecords.length; i++) {
if(arrayRecords[ i].equals(arrayFiltro[ i]))
objetosFiltrados.add(arrayRecords[ i]);
}
return objetosFiltrados;
}
¿Solucionado?
Pues no, hay otro problema que no he comentado antes.
Estás usando el mismo índice para recorrer los dos arrays y comparar sus elementos.
Esto en realidad, conlleva dos problemas:
1- Hay elementos que no se comparan entre ellos. Como solo usas un índice, el elemento de la posición[ 0] del arrayRecord, solo se compara con el elemento [ 0] de arrayFiltro.
Pero no se compara con [ 1], ni con [ 2].., ni con ningún otro.
2- Como los arrays tienen longitudes distintas, se va a producir una Excepción (un error) cuando el índice intente apuntar a elementos que no existen.
arrayRecord es más grande, longitud 5, así que tiene las posiciones: [ 0], [ 1], [ 2], [ 3] y [ 4]
Pero arrayFiltro solo tiene longitud 2, o sea, posiciones [ 0] y [ 1].
Cuando el índice intente comparar las posiciones [ 2] de ambos arrays, no podrá porque arrayFiltro no tiene. Y eso interrumpirá el programa con un mensaje de error.
Ambos problemas se pueden solucionar usando
dos bucles anidadosDe esta forma, cada array tiene su propio índice, el cuál solo apuntará a posiciones que sí existen.
Y además, se garantizan todas las posibles comparaciones, porque por cada repetición del bucle principal, el bucle anidado hará un recorrido completo del segundo array. Así cada elemento del primer array, se comparará con TODOS los elementos del segundo array.
public static ArrayList<Salud> filtrados(Salud[] arrayRecords) {
ArrayList<Salud> objetosFiltrados = new ArrayList<>();
for(int i=0; i<arrayRecords.length; i++) { //Bucle principal, recorre arrayRecord
for (int j=0; j<arrayFiltro.length; j++) { //Bucle anidado, recorre arrayFiltro
if(arrayRecords[ i].equals(arrayFiltro[j])) //Cada array usa su propio indice
objetosFiltrados.add(arrayRecords[ i]);
}
}
return objetosFiltrados;
}
Por último, volviendo a la clase
Salud.
Esta clase se supone representa un "objeto de salud" y consta de dos ítems.
Vale, eso me parece bien.
Lo que no tiene sentido es que tenga como atributo un array de objetos Salud.
En el mundo real, ¿un Tensiómetro contiene dentro a su vez una serie de otros objetos como Glucosa o Gasas?
No tiene sentido, ¿verdad?
Si no lo tiene en el mundo real, tampoco lo tiene en el código.
Su método display() tampoco tiene sentido. Un objeto Salud no tiene que saber que objetos han sido filtrados y cuáles no.
Su existencia ha de ser ajena a ese tema, de eso ya se ocupa la clase Filtro.
Su método display() lo único que ha de hacer es mostrar los datos de ESTE(this) objeto, lo que pase con otros objetos ajenos a él, ni le va ni le viene.
class Salud {
public final String item;
public final String item2;
private Salud[] arrayRecords;
public Salud(String item, String item2){
this.item = item;
this.item2 = item2;
}
public void display(){
System.out.println("Los record que coinciden son: " + Filtro.filtrados(arrayRecords));
}
public String getItem() {
return this.item;
}
public String getItem2() {
return this.item2;
}
@Override
public boolean equals(Object objeto) {
if (objeto instanceof Salud) { //Si objeto recibido es de clase Salud...
//Lo instanciamos como Salud
Salud otroObjeto = (Salud) objeto;
//Si al menos uno de sus items coinciden, se considerarán iguales
if (this.item.equals(otroObjeto.item) || this.item.equals(otroObjeto.item2)
|| this.item2.equals(otroObjeto.item) || this.item2.equals(otroObjeto.item2))
return true;
else
return false; //Ningún item coincide
}
else
return false; //Objeto recibido no es clase Salud
}
}
Mejor dejarlo así:
class Salud {
public final String item;
public final String item2;
public Salud(String item, String item2){
this.item = item;
this.item2 = item2;
}
public void display(){
System.out.println("Item 1: " + this.item + " -- Item 2: " + this.item2);
}
public String getItem() {
return this.item;
}
public String getItem2() {
return this.item2;
}
@Override
public boolean equals(Object objeto) {
if (objeto instanceof Salud) { //Si objeto recibido es de clase Salud...
//Lo instanciamos como Salud
Salud otroObjeto = (Salud) objeto;
//Si al menos uno de sus items coinciden, se considerarán iguales
if (this.item.equals(otroObjeto.item) || this.item.equals(otroObjeto.item2)
|| this.item2.equals(otroObjeto.item) || this.item2.equals(otroObjeto.item2))
return true;
else
return false; //Ningún item coincide
}
else
return false; //Objeto recibido no es clase Salud
}
}
Y con todos estos cambios, el programa ya corre y parece cumplir con lo que se le ha pedido.
Siento si he escrito demasiado, pero corregir sin explicar motivos, sería una oportunidad perdida para aprender.
Revísalo con calma todo y pregunta lo que necesites.
Un saludo.