有人能解释java HashMap的这种奇怪行为吗?
我在Java中经常使用HashMap,但从未遇到过这种行为。我必须输入,项目和项目组。它们的定义如以下代码片段所示
public class Item {
String id;
float total;
}
public class ItemGroup {
String keyword;
int frequency;
List<Item> items;
}
因此,ItemGroup由0项目。这些项目有一个共同的关键字,该关键字以一定的频率出现在系统中。有趣的是,我有下面的方法,给定一个项目列表,创建一个组列表
public static ItemGroup[] createGroups(Item[] items){
HashMap<String, ItemGroup> groups = new HashMap<String, ItemGroup>();
String[] words;
for (int i=0; i<items.length; i++){
words = items[i].getId().split(REGEX);
// Process keywords
for (int j=0; j<words.length; j++){
if (words[j].isEmpty()) break;
ItemGroup group = groups.get(words[j]);
if (group != null){
group.incrementFrequency();
group.getItems().add(items[i]);
}else {
group = EconomFactory.eINSTANCE.createItemGroup();
group.setKeyword(words[j]);
group.incrementFrequency();
group.getItems().add(items[i]);
groups.put(words[j], group);
}
}
}
return groups.values().toArray(new ItemGroup[0]);
}
奇怪的是,将项目添加到项目组(line group.getItems())时。添加(项[i]);)。在重新洗牌的过程中,团队以一种奇怪的方式丢失了物品。通过调试,我可以看到组在操作刚结束时包含了该项,但后一个选项处于打开状态,例如,当返回该方法的值时,所有组都丢失了它们的项
我试过这个:
public static ItemGroup[] createGroups(Item[] items){
HashMap<String, ItemGroup> groups = new HashMap<String, ItemGroup>();
String[] words;
for (int i=0; i<items.length; i++){
words = items[i].getId().split(REGEX);
// Create a new item based on the current one in the list
Item item = EconomFactory.eINSTANCE.createItem();
item.setId(items[i].getId());
item.setTotal(items[i].getTotal());
// Process key words
for (int j=0; j<words.length; j++){
if (words[j].isEmpty()) break;
ItemGroup group = groups.get(words[j]);
if (group != null){
group.incrementFrequency();
group.getItems().add(item);
}else {
group = EconomFactory.eINSTANCE.createItemGroup();
group.setKeyword(words[j]);
group.incrementFrequency();
group.getItems().add(item);
groups.put(words[j], group);
}
}
}
return groups.values().toArray(new ItemGroup[0]);
}
但是得到了同样的结果。然而,下面的解决方案效果很好
public static ItemGroup[] createGroups(Item[] items){
HashMap<String, ItemGroup> groups = new HashMap<String, ItemGroup>();
String[] words;
for (int i=0; i<items.length; i++){
words = items[i].getId().split(REGEX);
// Process key words
for (int j=0; j<words.length; j++){
if (words[j].isEmpty()) break;
// Create a new item based on the current one in the list
Item item = EconomFactory.eINSTANCE.createItem();
item.setId(items[i].getId());
item.setTotal(items[i].getTotal());
ItemGroup group = groups.get(words[j]);
if (group != null){
group.incrementFrequency();
group.getItems().add(item);
}else {
group = EconomFactory.eINSTANCE.createItemGroup();
group.setKeyword(words[j]);
group.incrementFrequency();
group.getItems().add(item);
groups.put(words[j], group);
}
}
}
return groups.values().toArray(new ItemGroup[0]);
}
这种方法在工厂里是可行的。爱因斯坦。createItemGroup()的实现如下:
public ItemGroup createItemGroup() {
ItemGroupImpl itemGroup = new ItemGroupImpl();
return itemGroup;
}
其中ItemGroupImpl是ItemGroup的实现,即它是ItemGroup的子类。这是因为我使用EMF(Eclipse建模框架)
谁能解释一下这种行为(为什么ItemGroup对象会丢失它们的项目)
下面是ItemGroup和ItemGroupImpl的代码。以同样的方式查找Item和ItemImpl的代码
public interface ItemGroup extends EObject {
String getKeyword();
void setKeyword(String value);
int getFrequency();
void setFrequency(int value);
EList<Item> getItems();
void incrementFrequency();
}
public class ItemGroupImpl extends EObjectImpl implements ItemGroup {
protected static final String KEYWORD_EDEFAULT = null;
protected String keyword = KEYWORD_EDEFAULT;
protected static final int FREQUENCY_EDEFAULT = 0;
protected int frequency = FREQUENCY_EDEFAULT;
protected EList<Item> items;
protected ItemGroupImpl() {
super();
}
@Override
protected EClass eStaticClass() {
return EconomPackage.Literals.ITEM_GROUP;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String newKeyword) {
String oldKeyword = keyword;
keyword = newKeyword;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET,
EconomPackage.ITEM_GROUP__KEYWORD, oldKeyword, keyword));
}
public int getFrequency() {
return frequency;
}
public void setFrequency(int newFrequency) {
int oldFrequency = frequency;
frequency = newFrequency;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET,
EconomPackage.ITEM_GROUP__FREQUENCY, oldFrequency, frequency));
}
public EList<Item> getItems() {
if (items == null) {
items = new EObjectContainmentEList<Item>(Item.class, this,
EconomPackage.ITEM_GROUP__ITEMS);
}
return items;
}
public void incrementFrequency() {
this.frequency = getFrequency() + 1;
}
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID,
NotificationChain msgs) {
switch (featureID) {
case EconomPackage.ITEM_GROUP__ITEMS:
return ((InternalEList<?>)getItems()).basicRemove(otherEnd,
msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case EconomPackage.ITEM_GROUP__KEYWORD:
return getKeyword();
case EconomPackage.ITEM_GROUP__FREQUENCY:
return getFrequency();
case EconomPackage.ITEM_GROUP__ITEMS:
return getItems();
}
return super.eGet(featureID, resolve, coreType);
}
@SuppressWarnings("unchecked")
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case EconomPackage.ITEM_GROUP__KEYWORD:
setKeyword((String)newValue);
return;
case EconomPackage.ITEM_GROUP__FREQUENCY:
setFrequency((Integer)newValue);
return;
case EconomPackage.ITEM_GROUP__ITEMS:
getItems().clear();
getItems().addAll((Collection<? extends Item>)newValue);
return;
}
super.eSet(featureID, newValue);
}
@Override
public void eUnset(int featureID) {
switch (featureID) {
case EconomPackage.ITEM_GROUP__KEYWORD:
setKeyword(KEYWORD_EDEFAULT);
return;
case EconomPackage.ITEM_GROUP__FREQUENCY:
setFrequency(FREQUENCY_EDEFAULT);
return;
case EconomPackage.ITEM_GROUP__ITEMS:
getItems().clear();
return;
}
super.eUnset(featureID);
}
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case EconomPackage.ITEM_GROUP__KEYWORD:
return KEYWORD_EDEFAULT == null ? keyword != null :
!KEYWORD_EDEFAULT.equals(keyword);
case EconomPackage.ITEM_GROUP__FREQUENCY:
return frequency != FREQUENCY_EDEFAULT;
case EconomPackage.ITEM_GROUP__ITEMS:
return items != null && !items.isEmpty();
}
return super.eIsSet(featureID);
}
@Override
public String toString() {
if (eIsProxy()) return super.toString();
StringBuffer result = new StringBuffer();
result.append("(keyword: ");
result.append(keyword);
result.append(", frequency: ");
result.append(frequency);
result.append(')');
return result.toString();
}
}
# 1 楼答案
在你的第二套代码中,我在哪里初始化
在这个上下文中,变量i还没有初始化,所以它可以是任何值(因为它没有爆炸,我假设你的代码中还有一个全局“i”,并且你用这个值0来启动你的方法
在正在运行的代码中,在访问方法之前,我已在该方法中进行了初始化:
所以,这就是我的猜测,为什么你会看到你看到的行为。。。总是在访问变量之前初始化它们
# 2 楼答案
请告诉我们工厂里发生了什么。爱因斯坦。createItemGroup()?我无法判断是否每次都创建了具有唯一项列表的唯一实例
我做了一些修改(我目前没有使用Java6,所以不能使用String.isEmpty),并假设定期创建对象,这对我来说是可行的。请参见下面我的runnable示例(类似于下次提问时应该发布的内容):
输出: