我正在尝试创建一个方法来计算Flower对象的数量(创建一个名为flower btw的类),该方法返回对象花阵列中特定花的数量。
我正在使用HashMap将整数(总和)映射到一个键(键是花对象)。但是,当我输出数组时,堆中键的内存地址与HashMap表中键的位置一起。
然而,我的意图是打印花(主要是名称),该数组中的花朵数量与Flower Object类型相同。
我的代码如下:
private void displayFlowers(Flower flowerPack[]) {
// TODO: Display only the unique flowers along with a count of any
// duplicates
/*
* For example it should say Roses - 7 Daffodils - 3 Violets - 5
*/
HashMap<Flower, Integer> flowerFrequency = new HashMap<Flower, Integer>();
for (Flower aFlower : flowerPack) {
if (flowerFrequency.containsKey(aFlower)) {
Integer i = flowerFrequency.get(aFlower);
i++;
} else {
flowerFrequency.put(aFlower, new Integer(1));
}
}
System.out.println(flowerFrequency);
}
输出如下:
1: Add an item to the pack.
2: Remove an item from the pack.
3: Search for a flower.
4: Display the flowers in the pack.
0: Exit the flower pack interfact.
4
{null=1, Flower@6bc7c054=1, Flower@42a57993=1, Flower@75b84c92=1}
按照说明,我还将toString()和equals()方法添加到Flower类中,如下所示:
我在Flower类中添加了toString()和equals()方法,如下所示:
public String toString() {
return this.color + " " + this.name + " smells like " + this.scentType + " is Thorny " + this.hasThorns;
}
@Override
public boolean equals(Object otherFlower) {
if (otherFlower == null) {
return false;
}
if (!Flower.class.isAssignableFrom(otherFlower.getClass())) {
return false;
}
final Flower other = (Flower) otherFlower;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (!(this.color.equals(other.color))) {
return false;
}
if (!(this.scentType.equals(other.scentType))) {
return false;
}
if (this.hasThorns != other.hasThorns) {
return false;
}
return true;
}
答案 0 :(得分:2)
除了覆盖toString()以返回您想要阅读的字符串外,您的代码还包含一个真正的错误:
if (flowerFrequency.containsKey(aFlower)) {
Integer i = flowerFrequency.get(aFlower);
i++;
不行。你看,Integer对象是不可变的。你的代码从地图中取出计数器,将那个东西变成一个int(上面甚至编译了吗?!)......然后忘了它!您无法修改存储在该地图中的整数的值,而是必须将更新的值放回地图中:
if (flowerFrequency.containsKey(aFlower)) {
Integer currentCounter = flowerFrequency.get(aFlower);
flowerFrequency.put(aFlower, currentCounter+1);
编辑:当然,为了使Map真正适用于您的花对象,您必须为equals()/ hashCode()提供有意义的覆盖(有关指导,请参阅here)。
答案 1 :(得分:1)
问题似乎在于你如何与地图互动。您通过Integer
的构造函数包装int(由于自动装箱而不必要),并且您正在递增值但从不将其放回。
if (flowerFrequency.containsKey(aFlower)) {
Integer i = flowerFrequency.get(aFlower); //uses two lookups
i++; //only increments our immediate value, not the object
} else {
flowerFrequency.put(aFlower, new Integer(1)); //does not need wrapping
}
理想情况下,您需要检索一次并放置一次。当没有密钥映射时,HashMap
会返回null
,因此您可以利用它来获取优势:
Integer amount = flowerFrequency.get(aFlower);
if (amount == null) {
amount = 0;
}
flowerFrequency.put(aFlower, amount + 1);
通过Java 8缩短:
Integer amount = flowerFrequency.getOrDefault(aFlower, 0); //default 0 for no value
flowerFrequency.put(aFlower, amount + 1);
至于简化问题,Collectors有一个很好的实用工具:
Map<Flower, Integer> frequency = Arrays.stream(flowerPack)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(t -> 1)));
但如果您仍然喜欢使用循环,那么Map#compute
也可以使用单行解决方案:
Map<Flower, Integer> frequency = new HashMap<>();
for (Flower f : flowerPack) {
frequency.compute(f, (key, old) -> old == null ? 1 : old + 1); //increment
}
答案 2 :(得分:0)
如果你没有覆盖toString()(来自java.lang.Object),当你将对象打印到console / log时,它只是打印对象的十六进制表示(如Flower @ 6bc7c054等)。 )。但是,您可以通过覆盖toString
类中的Flower
()方法来覆盖此默认行为,以实际提供名称。
public class Flower {
private String name;
//other flower variables
public String toString() {
return name;
}
}
public String toString():返回的字符串表示形式 宾语。通常,toString方法返回一个字符串 “文字表示”这个对象。
请在这里参考toString()api https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html