Cambio del valor del objeto ArrayList debido al mismo código hasch (objetos duplicados)

Estoy creando una lista de matriz de objetos y agregando esos objetos al azar:

public ArrayList makePerks(int roun, int ran) {
    perks.clear();
    int perkAm = Menu.randInt(6, 7);
    Perk last = new Perk();
    for (int i = 0; i < perkAm; ++i) {
        Perk tempPerk = new Perk();
        tempPerk = generate(ran, roun);
        System.out.println(tempPerk.name + " - " + tempPerk.cost);
        perks.add(tempPerk);
    }
    System.out.println("_________________________");
    return perks;
}

Lo que esto hace es crear beneficios aleatoriamente usando algunas otras funciones. El resultado de la declaración de impresión en esto es el siguiente:

12-11 01:51:07.331: I/System.out(3900): Gain Profit - 4
12-11 01:51:07.341: I/System.out(3900): Strength - 11
12-11 01:51:07.351: I/System.out(3900): Gain Profit - 5
12-11 01:51:07.361: I/System.out(3900): High Premium - 17
12-11 01:51:07.371: I/System.out(3900): Moderate Speed - 5
12-11 01:51:07.381: I/System.out(3900): Nomad - 11
12-11 01:51:07.381: I/System.out(3900): _________________________

Ahora, dentro de una de mis actividades (Android), recupero la lista de matrices que se devuelve de la función anterior:

tempItems = perkGen.makePerks(plrRound, plrRank);

Y ahora quiero agregar los datos a un adaptador ArrayList usando un bucle for así:

        for (int i = 0; i < tempItems.size(); ++i) {
        shopItems.add(tempItems.get(i));
        System.out.println(tempItems.get(i).name + " - " + tempItems.get(i).cost);
        perk_adapter.notifyDataSetChanged();
    }

Todo funciona bien, excepto que la salida es la siguiente:

12-11 01:51:07.381: I/System.out(3900): Gain Profit - 5
12-11 01:51:07.391: I/System.out(3900): Strength - 11
12-11 01:51:07.391: I/System.out(3900): Gain Profit - 5
12-11 01:51:07.391: I/System.out(3900): High Premium - 17
12-11 01:51:07.391: I/System.out(3900): Moderate Speed - 5
12-11 01:51:07.391: I/System.out(3900): Nomad - 11

Si no te has dado cuenta, donde tengo 2 duplicados; (Gain Profit) en la primera salida son 4 y 5, pero en la segunda son 5 y 5. ¿Cómo es esto posible? ¿Tiene esto algo que ver con que haya 2 objetos similares en la matriz? ¿O es algo que estoy haciendo mal?

Aquí están las mismas salidas con códigos hash:

12-11 02:25:31.281: I/System.out(4024): Moderate Speed - 8 - -1307644808
12-11 02:25:31.291: I/System.out(4024): Agility - 9 - -1307646728
12-11 02:25:31.301: I/System.out(4024): Agility - 5 - -1307647072
12-11 02:25:31.301: I/System.out(4024): Prolix - 13 - -1307638016
12-11 02:25:31.321: I/System.out(4024): IDA - 5 - -1307641072
12-11 02:25:31.321: I/System.out(4024): Moderate Speed - 11 - -1307644808
12-11 02:25:31.321: I/System.out(4024): _________________________
12-11 02:25:31.321: I/System.out(4024): Moderate Speed - 11 - -1307644808
12-11 02:25:31.321: I/System.out(4024): Agility - 9 - -1307646728
12-11 02:25:31.321: I/System.out(4024): Agility - 5 - -1307647072
12-11 02:25:31.321: I/System.out(4024): Prolix - 13 - -1307638016
12-11 02:25:31.321: I/System.out(4024): IDA - 5 - -1307641072
12-11 02:25:31.331: I/System.out(4024): Moderate Speed - 11 - -1307644808

También puede notar que en la salida anterior, la agilidad mantiene la salida correcta, pero la velocidad moderada no lo hace. Esto se debe a que los códigos hash son los mismos para los elementos de agilidad. ¿Cómo se puede evitar o cambiar esto?

Gracias por tu ayuda :)

Si necesito publicar más código, solo pregunte :) Pero espero que tenga toda la información que necesita :) Gracias de nuevo :)

Otra adición al código según lo solicitado EL MÉTODO GENERATE:

public Perk generate(int ran, int roun) {
    final DecimalFormat mb = new DecimalFormat("0.00");
    int perkT = Menu.randInt(0, 4);
    Perk tempPerk = new Perk();

    if (perkT == 0) { // Speed
        ArrayList tempArray = new ArrayList();
        tempArray = getSpeedPerks(ran, roun);
        Perk tePerk = new Perk();
        tePerk = getPerk(tempArray);
        tempPerk = tePerk;
        int randBonus = Menu.randInt(0, 3);
        tempPerk.cost += randBonus;
        // Perk Increase Formula:
        double lvlBonus = roun * ran;
        double lvlInc = lvlBonus / 10;
        double bon = 1.0 + lvlInc;
        tempPerk.plusInc *= (bon);
        tempPerk.cost *= (bon);
        tempPerk.desc = ("Increases the effectiveness of each tap:\n"
                + "    - Tap Power + " + mb.format(tempPerk.plusInc));

    }
    if (perkT == 1) { // Minus
        ArrayList tempArray = new ArrayList();
        tempArray = getMinusPerks(ran, roun);
        Perk tePerk = new Perk();
        tePerk = getPerk(tempArray);
        tempPerk = tePerk;
        int randBonus = Menu.randInt(0, 3);
        tempPerk.cost += randBonus;
        // Perk Increase Formula:
        double lvlBonus = roun * ran;
        double lvlInc = lvlBonus / 10;
        double bon = 1.0 + lvlInc;
        tempPerk.minusDec *= (bon);
        tempPerk.cost *= (bon);
        tempPerk.desc = ("Decreases the bars speed:\n"
                + "   - Bar Speed - " + mb.format(tempPerk.minusDec));
    }
    if (perkT == 2) { // Auto
        ArrayList tempArray = new ArrayList();
        tempArray = getAutoPerks(ran, roun);
        Perk tePerk = new Perk();
        tePerk = getPerk(tempArray);
        tempPerk = tePerk;
        int randBonus = Menu.randInt(0, 3);
        tempPerk.cost += randBonus;
        // Perk Increase Formula:
        if (roun > 0 & roun <= 5) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 30;
                tempPerk.clickAmount = 1;
            } else {
                tempPerk.autoClick = 60;
                tempPerk.clickAmount = 2;
            }
        } else if (roun > 5 & roun <= 10) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 20;
                tempPerk.clickAmount = 1;
            } else {
                tempPerk.autoClick = 60;
                tempPerk.clickAmount = 3;
            }
        } else if (roun > 10 & roun <= 15) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 15;
                tempPerk.clickAmount = 1;
            } else {
                tempPerk.autoClick = 20;
                tempPerk.clickAmount = 2;
            }
        } else if (roun > 15 & roun <= 20) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 10;
                tempPerk.clickAmount = 1;
            } else {
                tempPerk.autoClick = 20;
                tempPerk.clickAmount = 2;
            }
        } else if (roun > 20 & roun <= 24) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 5;
                tempPerk.clickAmount = 1;
            } else {
                tempPerk.autoClick = 10;
                tempPerk.clickAmount = 2;
            }
        } else if (roun == 25) {
            int rand = Menu.randInt(0, 1);
            if (rand == 0) {
                tempPerk.autoClick = 5;
                tempPerk.clickAmount = 2;
            } else {
                tempPerk.autoClick = 3;
                tempPerk.clickAmount = 1;
            }
        } else if (ran == 2) {
            int rand = Menu.randInt(0, 2);
            if (rand == 0) {
                tempPerk.autoClick = 5;
                tempPerk.clickAmount = 2;
            }
            if (rand == 1) {
                tempPerk.autoClick = 3;
                tempPerk.clickAmount = 1;
            }
            if (rand == 2) {
                tempPerk.autoClick = 2;
                tempPerk.clickAmount = 1;
            }
        } else if (ran == 3) {
            tempPerk.autoClick = 1;
            tempPerk.clickAmount = 1;
        } else {
            tempPerk.autoClick = 1;
            tempPerk.clickAmount = 1;
        }
        tempPerk.desc = ("Auto Taps at a fixed rate:\n" + "   - Taps + "
                + mb.format(tempPerk.clickAmount) + "\n   - every "
                + tempPerk.autoClick + " seconds");
    }
    if (perkT == 3) { // Reward
        ArrayList tempArray = new ArrayList();
        tempArray = getRewardPerks(ran, roun);
        Perk tePerk = new Perk();
        tePerk = getPerk(tempArray);
        tempPerk = tePerk;
        int randBonus = Menu.randInt(0, 3);
        tempPerk.cost += randBonus;
        // Perk Increase Formula:
        double lvlBonus = roun * ran;
        double lvlInc = lvlBonus / 10;
        double bon = 1.0 + lvlInc;
        tempPerk.cost *= (bon);
        tempPerk.rewardBonus += lvlInc / 5;
        tempPerk.desc = ("Increases amount of tokens gathered at the end of each round:\n"
                + "   - Tokens + " + tempPerk.rewardBonus);
    }
    if (perkT == 4) { // All Rounder
        ArrayList tempArray = new ArrayList();
        tempArray = getAllRounPerks(ran, roun);
        Perk tePerk = new Perk();
        tePerk = getPerk(tempArray);
        tempPerk = tePerk;
        int randBonus = Menu.randInt(0, 3);
        tempPerk.cost += randBonus;
        // Perk Increase Formula:
        double lvlBonus = roun * ran;
        double lvlInc = lvlBonus / 10;
        double bon = 1.0 + lvlInc;
        tempPerk.plusInc *= (bon);
        tempPerk.minusDec *= (bon);
        tempPerk.cost *= (bon);
        tempPerk.desc = ("Increases the effectiveness of several stats:\n"
                + "   - Tap Power + " + mb.format(tempPerk.plusInc)
                + "\n   - Bar Speed - " + mb.format(tempPerk.minusDec)
                + "\n   - Tokens + " + tempPerk.rewardBonus);
    }
    return tempPerk;
}

Esta línea aquí:

tePerk = getPerk(tempArray);

Hace que el tePerk sea igual a un beneficio de una lista, esto puede estar causando el problema.

Gracias de nuevo :)

preguntado el 11 de diciembre de 13 a las 07:12

Hola, ¿por qué has usado el código ` Perk last = new Perk(); ` y ¿vas a acceder a la variable de instancia de beneficios en cualquier lugar? -

Perk tempPerk = new Perk(); Esta línea es inútil ya que está cambiando tempPerk con esta línea tempPerk = generate(ran, roun); -

Ey. No estoy usando last en este momento, no está relacionado con el código actual. Pero lo usaré más tarde. Y sí, tempPerk se genera en la función generar () como puede ver: tempPerk = generar () -

a pesar de todo eso, me está dando el valor correcto la primera vez que lo imprimo, por lo que no debería tener nada que ver con la forma en que lo genero, ¿verdad? -

puedes ver imprimiendo el tempItems.get(i).hashcode() también -

4 Respuestas

¿Puedes publicar el código para generar el método?
No estoy seguro, pero según el código que haya proporcionado, parece que en el método de generación está reutilizando el objeto, por ejemplo: la primera ventaja devuelta con el nombre "Velocidad moderada" y cuesta 1 y lo agrega a la lista e incluso lo imprime . Luego, nuevamente, se usa el mismo objeto para "Velocidad moderada" con valor 8 y lo agrega a la lista e imprime... Ahora la lista tiene 11 mismos objetos de ventajas.

Desde la primera vez que está agregando e imprimiendo un beneficio a la vez, está viendo 1 valores diferentes. Y la segunda vez que imprime todos los valores en un bucle for y, por lo tanto, está viendo los mismos valores.

Respondido el 11 de diciembre de 13 a las 07:12

Publicaré el método de generación. PERO es extraño cómo no sucedió lo mismo para el segundo ejemplo con agilidad y velocidad moderada. - usuario3011902

El problema parece ser que algunos objetos comparten el mismo código hash. Es confuso que algunas entradas compartan el mismo código hash cuando otras no. Eché un vistazo a estos enlaces, pero no fueron muy útiles, pero es un problema con el código hash:

http://www.devmanuals.com/tutorials/java/collections/ListHashCode.html

y

ArrayList: agregue "mismos" objetos (igual => igual, hashCode), subprocesos

Gracias Sateesh Cheveri

Esta línea:

tePerk = getPerk(tempArray); 

Hace que el objeto teTerk sea igual a un beneficio de una lista. Lo que puede estar causando que tenga el mismo código hash si dos ventajas obtienen el mismo elemento de esa lista. Sin embargo, no estoy seguro de cómo solucionarlo.

Esta no es la respuesta, pero sé cuál es el problema ahora.

contestado el 23 de mayo de 17 a las 13:05

1) Faltan algunos detalles en la pregunta. Sin embargo, supongo que shopItems es un HashSet y está intentando copiar todos los elementos de una ArrayList en él.

Al copiar entre colecciones, tenga en cuenta que mientras que las listas de arreglos aceptan duplicados, los conjuntos no. Los duplicados están determinados por el método equals(), por lo que suponiendo que x.equals(y), intentar agregar x a un conjunto que contiene y fallará.

Haga que su Perk.equals() refleje la verdadera identidad de sus instancias, de modo que los "duplicados" ocurran solo cuando espera que ocurran (y luego adapte el hashcode() en consecuencia).

2) su método makePerks() parece usar un miembro de datos, en lugar de crear una nueva lista. Esto puede causar problemas, porque la lista devuelta puede cambiar inesperadamente en algún momento después de la invocación. Esto puede explicar el cambio que ve.

Respondido el 11 de diciembre de 13 a las 08:12

Bien, solucioné el problema. El problema era que estaba recuperando los objetos de otra lista de arreglos. Imagine que tiene una ArrayList llamada A. Y otra llamada B. Imagine que está recuperando Objetos de la ArrayList A y moviéndolos a través de B. Si recupero el mismo objeto de A dos veces y lo muevo a B, dentro de B los dos objetos tendrá el mismo código hash que causará problemas.

Entonces, para arreglar eso, hice un nuevo objeto puente que hereda todos los valores de los objetos que salen de a y luego pasa el nuevo objeto a B en lugar de mover directamente los objetos de A. Hice esto así:

public Perk getPerk(ArrayList<Perk> perks) {
    Perk tempPerk = new Perk();
    Perk newMPerk = new Perk();
    ArrayList<Perk> tempPerks = new ArrayList();
    tempPerks.clear();
    int random = Menu.randInt(1, 100);
    for (int i = 0; i < perks.size(); ++i) {
        if (hasRar(perks.get(i), random)) {
            tempPerks.add(perks.get(i));
        }
    }
    if (tempPerks.isEmpty() == false) {
        int nextRandom = Menu.randInt(0, tempPerks.size() - 1);
        tempPerk = tempPerks.get(nextRandom);
        newMPerk.name = tempPerk.name;
        newMPerk.cost = tempPerk.cost;
        newMPerk.rarity = tempPerk.rarity;
        newMPerk.minusDec = tempPerk.minusDec;
        newMPerk.plusInc = tempPerk.plusInc;
        newMPerk.rewardBonus = tempPerk.rewardBonus;

    } else {
        Perk newPerk = new Perk();
        newPerk.name = "Extra";
        newPerk.cost = 0;
        newPerk.rarity = 1;
        newPerk.minusDec = 0;
        newPerk.plusInc = 0;
        newPerk.rewardBonus = 0;
        newMPerk = newPerk;
    }
    return newMPerk;
}

Entonces, NewMPerk hereda todas las variables: nombre, costo, etc. Del objeto que se recupera de la lista de matrices A. Y luego se devuelve y se agrega a la lista de matrices B. Dado que NewMPerk es un nuevo objeto del tipo Perk, tendrá un hashCode diferente cada vez.

Espero que esto pueda ayudar a otras personas :)

Si tiene alguna pregunta, sientase con libertad de preguntar :)

Respondido el 12 de diciembre de 13 a las 02:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.