【问题标题】:ArrayList Object Value Change due to same HaschCode (Duplicate Objects)由于相同的 HaschCode(重复对象)导致 ArrayList 对象值更改
【发布时间】:2013-12-29 00:56:47
【问题描述】:

我正在创建一个对象数组列表并将这些对象随机添加到其中:

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;
}

它的作用是使用其他一些功能随机创建津贴。这里的 Print 语句的输出如下:

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): _________________________

现在在我的一个活动 (android) 中,我检索从上述函数返回的数组 List:

tempItems = perkGen.makePerks(plrRound, plrRank);

现在我想使用 for 循环将数据添加到 ArrayList 适配器,如下所示:

        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();
    }

一切正常,除了输出如下:

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

如果您没有注意到,我有 2 个重复项; (Gain Profit) 在第一个输出中,它们是 4 和 5,但在第二个输出中,它们是 5 和 5。这怎么可能?这是否与数组中有 2 个相似的对象有关?还是我做错了什么?

以下是带有哈希码的相同输出:

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

您可能还注意到,在上面的输出中,敏捷保持正确的输出,而中等速度却没有。这是因为敏捷项目的哈希码是相同的。如何避免或改变这种情况?

感谢您的帮助:)

如果我需要发布更多代码,请询问 :) 但我希望您拥有所需的所有信息 :) 再次感谢:)

根据要求对代码的另一个添加生成方法:

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;
}

这里的这一行:

tePerk = getPerk(tempArray);

使 tePerk 等于列表中的 perk,这可能会导致问题。

再次感谢您:)

【问题讨论】:

  • 嗨,为什么你使用了代码` Perk last = new Perk(); ` 你打算在任何地方访问 perks 实例变量吗?
  • Perk tempPerk = new Perk(); 这条线没用,因为你正在用这条线 tempPerk = generate(ran, roun); 更改 tempPerk
  • 嘿。我目前没有使用 last 它与当前代码无关。但我稍后会使用它。是的 tempPerk 是在 generate() 函数中生成的,如您所见: tempPerk = generate()
  • 尽管它在我第一次打印出来时给了我正确的价值,所以它不应该与我如何正确生成它有关?
  • 你能看到打印tempItems.get(i).hashcode()

标签: java android arrays arraylist


【解决方案1】:

你能发布生成方法的代码吗?
我不确定,但从您提供的任何代码来看,看起来在生成方法中您正在重用该对象,例如:第一次返回的 perk 名称为“中等速度”,成本为 8,然后您将其添加到列表和甚至打印它。然后再次将相同的对象用于值为 11 的“中等速度”,然后将其添加到列表并打印它...现在列表有 2 个相同的特权对象。

自从您第一次添加和打印一项福利以来,您会看到 2 个不同的价值。第二次在 for 循环中打印所有值,因此您会看到相同的值。

【讨论】:

  • 我将发布生成方法。但是奇怪的是,第二个例子没有发生同样的事情,但速度适中。
【解决方案2】:

问题似乎是某些对象共享相同的 hashCode。令人困惑的是,有些条目共享相同的哈希码,而其他条目却不共享。我查看了这些链接,但它们不是很有帮助,但它是哈希码的问题:

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

ArrayList - add "same" objects (same => equals, hashCode), Threads

谢谢萨提什·切维里

这一行:

tePerk = getPerk(tempArray); 

使 teTerk 对象等于列表中的特权。如果两个特权从该列表中获取相同的项目,这可能会导致它具有相同的 hashCode。不过不知道怎么解决。

这不是答案,但我知道现在是什么问题。

【讨论】:

    【解决方案3】:

    1)问题中缺少一些细节。但是,我假设 shopItems 是一个 HashSet,并且您正在尝试将 ArrayList 中的所有项目复制到其中。

    在集合之间进行复制时,请记住,虽然数组列表接受重复项,但集合不接受。重复项由 equals() 方法确定,因此假设 x.equals(y),尝试将 x 添加到包含 y 的集合将失败。

    让您的 Perk.equals() 反映您的实例的真实身份,以便“重复”仅在您期望它们发生时发生(然后相应地调整 hashcode())。

    2) 您的 makePerks() 方法似乎使用了数据成员,而不是创建新列表。这可能会引起麻烦,因为返回的列表可能会在调用后的某个时间点发生意外更改。这可以解释你看到的变化。

    【讨论】:

      【解决方案4】:

      好的,我解决了这个问题。问题是我正在从另一个数组列表中检索对象。因此,假设您有一个名为 A 的 ArrayList。另一个名为 B。因此,假设您正在从 ArrayList A 中检索对象并将它们移动到 B 中。如果我从 A 中检索相同的对象两次并将其移动到 B 中,则在 B 中这两个对象将具有相同的 hashCode ,这将导致问题。

      为了解决这个问题,我创建了一个新的桥接对象,它继承了来自 a 的对象的所有值,然后将新对象传递给 B,而不是直接移动 A 的对象。我是这样做的:

      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;
      }
      

      所以 NewMPerk 从 Array List A 中检索到的 Object 继承了所有变量:Name cost 等。然后将其返回并添加到 Array List B 中。由于 NewMPerk 是 Perk 类型的新 Object,它每次都会有不同的 hashCode。

      希望这可以帮助其他人:)

      如果您有任何问题,请随时提问:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-26
        • 1970-01-01
        • 2012-05-25
        • 2016-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-09
        相关资源
        最近更新 更多