我正在尝试为uni的家庭作业创建一个Locker类和一个Long Term Storage类。 他们两个都应该能够存储由我们的老师制作的具有体积和类型的Item对象。 (虽然每个储物柜的存储单元数量有限,而长期存储的设置数量为1000个单元。) 我正在尝试决定如何以最佳方式实现存储。 我考虑过只创建一个数组,因为我通常说1000个项目的顶部并不多,但是我想编写最好的,效率最高的代码,并且对其顺序并不重要。 我们只是了解了HashSets,所以我考虑过创建一个HashSet,这会使我的程序的运行变得更好。 问题是我需要保持每种存储的项目数量的计数,并且集合不允许重复。 因此,我想到了可能要创建一个长度为2的数组HashSet,以跟踪项目的类型及其在存储中的数量。
我不太确定实现这种存储的最佳方法是什么,也许我走的是绝对错误的方法。在我看来,当我要从1000种中查找特定种类的项目时,简单数组不是很有效。(如果长期存储中存储了1000种不同类型和数量为1的不同项目)
一个额外的问题:在本练习中,我应该使用TDD方法(测试驱动开发),并且不确定如何正确实现测试代码。帮助将不胜感激。 (应该与JUnit和Asserts一起使用。)
我的代码开头的示例:
import oop.ex3.spaceship.*;
import java.lang.reflect.Array;
import java.util.*;
public class Locker {
private static final int TOO_MANY_ITEMS = -1;
private static final int WORKED_WELL = 0;
private static final int MOVED_TO_LONG_TERM = 1;
private final int capacity;
private int currentLoad;
private HashSet<Item> itemsStored;
public Locker(int capacity){
this.capacity = capacity;
this.currentLoad = 0;
itemsStored = new HashSet<>();
}
public int addItem(Item item, int n){
if (currentLoad + n*item.getVolume() < capacity){
}
else{
return this.TOO_MANY_ITEMS;
}
return 0;
}
答案 0 :(得分:0)
考虑使用HashMap代替HashSet。具体来说,考虑
HashMap<KeyType, Object[]>
,或者甚至更好
HashMap<KeyType, ItemWrapper>
其中KeyType是Item类中的String,Integer或某种其他类型的唯一标识符,而ItemWrapper是用于存储相关数据的简单类。
您说您不想使用数组,因为您希望使用标识符(而不是添加顺序)快速检索。您还希望将商品“映射”到数量计数。 HashMap允许您将键与值相关联,以便快速查找。
我们将从一个过于简单的实现开始,然后使其变得更好。我还将展示如何按照您的要求使用大小为2的数组,即使这不是最佳方法。
在一个过于简单的实现中,您的密钥可能是您的Item,而您的值可能是数量。例如,
HashMap<Item, Integer> myHashMap = new HashMap<Item, Integer>(1400);
public int addItem(Item item, int n) {
//...
int currentCount = myHashMap.getOrDefault(item, 0);
myHashMap.put(item, n + currentCount);
//...
}
public int quantityOf(Item item) {
return myHashMap.getOrDefault(item, 0);
}
public boolean isInLocker(Item item) {
return myHashMap.containsKey(item);
//or return this.quantityOf(item) > 0;
}
(请注意,此代码依赖于autoboxing and unboxing,但如果愿意,也可以不编写它。此外,您可以调整哈希图的初始容量。初始容量为1400,负载因子为.75, HashMap中大约有1050个项目时,将调整大小。)
麻烦的是,然后您将需要已经拥有Item对象才能查找该项目,这在大多数情况下可能不切实际。 (或者,至少,您需要从hashCode()
得到的结果相同并且对于equals()
返回true的东西)。您可以在Item类中为@Overrides
和hashCode()
添加equals()
。但是,如果为您提供了Item类,则不允许您更改(或不希望更改),并且hashCodes()
和equals()
不能满足您的快速需求抬头?在这种情况下,您将必须具有不同的键,例如项目ID或唯一的描述符(例如,如果在程序中将所有“铅笔”项目都视为相同的字符串,则字符串将起作用)。
为了使您的梦想与HashMap一起工作,您需要一种独特的方式来标识Item对象-我们将以此为键。对于下面的示例代码,我假定标识符是字符串。您还需要一种将物料与数量关联的方法。
我建议不要使用Object [],而是将Item包装在一个新的简单类中,该类可以同时跟踪Item及其数量。例如:
class ItemWrapper {
Item item;
int quantity;
}
(我简化了示例,但您可以根据需要将成员设为私有,添加getter / setter等)。
这样,您的代码更具可读性,并且需要更少的强制转换。然后,将其与类似以下代码的代码一起使用:
HashMap<String, ItemWrapper> myHashMap = new HashMap<String, ItemWrapper>(1400);
public int addItem(Item item, int n) {
//...
ItemWrapper wrappedItem = myHashMap.get(item.uniqueID);
if (wrappedItem == null) {
wrappedItem = new ItemWrapper(item, n);
}
else {
wrappedItem.quantity += n;
}
myHashMap.put(item.uniqueID, wrappedItem);
//...
}
public int quantityOf(String itemID) {
ItemWrapper wrappedItem = myHashMap.get(itemID);
return wrappedItem == null ? 0 : wrappedItem.quantity;
}
public boolean isInLocker(String itemID) {
return myHashMap.containsKey(itemID);
//or return this.quantityOf(itemID) > 0;
}
在您的问题中,您询问了一个大小为2的数组。以上方法是我的建议,但是如果您必须使用数组,则可以执行以下代码:
HashMap<Item, Object[]> myHashMap = new HashMap<Item, Object[]>(1400);
public int addItem(Item item, int n) {
//...
Object[] itemBundle = myHashMap.get(item.uniqueID);
if (itemBundle == null) {
itemBundle = new Object[2];
itemBundle[0] = item;
itemBundle[1] = new Integer(n);
}
else {
itemBundle[2] = new Integer((Integer)itemBundle[2] + n);
}
myHashMap.put(item.uniqueID, itemBundle);
//...
}
public int quantityOf(String itemID) {
return myHashMap.getOrDefault(itemID, 0);
}
public boolean isInLocker(String itemID) {
return myHashMap.containsKey(itemID);
//or return this.quantityOf(itemID) > 0;
}
您最好将有关测试驱动开发的“额外问题”作为一个单独的问题进行研究。您是否在问如何从概念上讲解TDD或如何实际编写测试代码?无论哪种方式,您都可以通过搜索StackOverflow的现有内容找到不错的答案。