Я много раз использовал HashMap в Java, но никогда не сталкивался с таким поведением. У меня есть типы Item и ItemGroup . Они определены, как показано в следующих фрагментах кода.
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]);
}
Часть, где это становится странным, - при добавлении элемента в группу элементов (строка group.getItems (). Add (items [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]);
}
Метод EconomFactory.eINSTANCE.createItemGroup () реализован следующим образом:
public ItemGroup createItemGroup() {
ItemGroupImpl itemGroup = new ItemGroupImpl();
return itemGroup;
}
где ItemGroupImpl является реализацией ItemGroup, т.е. это подклассы ItemGroup. Это потому, что я использую EMF (Eclipse Modeling Framework).
Может ли кто-нибудь объяснить это поведение (почему объекты 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();
}
}