我正在尝试用新的修改版本替换集合中的元素。下面是简短的代码,旨在展示我想要实现的目标。
整个想法是我有一个由其他对象的集合组成的对象。在某个时间点,我期待集合中的这些对象(在我的示例手机中)可能需要一些修改,我只想在一个地方修改代码。
我知道为了更新对象的属性,我可以在迭代整个集合时使用setter,如下所示。但也许有更好,更通用的方法来实现这一点。
public class Customer {
private int id;
private Collection<Phone> phoneCollection;
public Customer() {
phoneCollection = new ArrayList<>();
}
//getters and setters
}
和电话课
public class Phone {
private int id;
private String number;
private String name;
//getters and setters
}
和
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Collection<Phone> col = c.getPhoneCollection();
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
// This is working fine
// phone.setNumber(p.getNumber());
// phone.setName(p.getName());
// But I'd like to replace whole object if possible and this is not working, at least not that way
phone = p;
}
}
System.out.println(c);
}
}
这可能实现我想要的吗? 我尝试了复制构造函数的想法和我在网上搜索的其他方法,但没有一个像我期望的那样工作。
编辑1
在阅读了一些评论之后,我有了一个想法
我将以下方法添加到我的Phone类
public static void replace(Phone org, Phone dst){
org.setName(dst.getName());
org.setNumber(dst.getNumber());
}
现在我的foreach部分看起来像那样
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
Phone.replace(phone, p);
}
}
它完成了这项工作。 现在,如果我更改Phone类属性,我只需要更改该方法。你认为以这种方式解决问题是否合适?
答案 0 :(得分:3)
在您重复使用该集合时,不应修改该集合;这可能会让你获得ConcurrentModificationException
。您可以扫描集合中第一个符合搜索条件的对象。然后你可以退出循环,删除旧对象,然后添加新对象。
Collection<Phone> col = c.getPhoneCollection();
Phone original = null;
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
original = phone;
break;
}
}
if (original != null) {
Phone replacement = new Phone(original);
replacement.setNumber(p.getNumber());
replacement.setName(p.getName());
col.remove(original);
col.add(replacement);
}
或者,您可以声明一种更具体的集合类型,例如List
,它允许您使用索引,这将使替换步骤更有效。
如果您的手机ID对每部手机都是唯一的,则应考虑使用Map<Integer, Phone>
将每个手机ID映射到相应的手机。 (或者,您可以使用某种第三方稀疏数组结构,不会将每个ID装入Integer
。)当然,如果您的ID不是唯一的,那么您可能会想修改上述内容以收集所有匹配手机的二级集合(并重新考虑现有代码的逻辑)。
答案 1 :(得分:1)
你也可以使用Set(HashSet),这只是在你不想做Mike建议的时候。
将手机用作套装中的项目。别忘了在Phone中实现hashCode()和equals()。 hashCode()应该返回id,因为它应该是唯一的。
由于您担心更换项目,所以HashSet将如何帮助您:
这两项操作2&amp;在O(1)/恒定时间内保证3。
您不需要为此问题维护地图,这是多余的。
如果你想从集合本身获取对象然后修改它,那么HashMap会更好,在O(1)时间内保证搜索。
答案 2 :(得分:0)
使用带有电话ID的map代替列表。然后您的代码如下所示:
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Map<Integer, Phone> phoneMap = c.getPhoneMap();
phoneMap.put(p.getId(), p);
System.out.println(c);
}
答案 3 :(得分:-1)
如果从集合中取出对象并更新其属性,它也会反映在集合中的同一个对象中。因此,您不必在更新后从技术上替换对象。 作为&#34; Mike M。&#34;指出,您可以使用hashmap快速检索对象而无需迭代并更新对象值。
答案 4 :(得分:-2)
如果订单对您很重要,您可以将Collection
更改为List
(因为您始终使用ArrayList
),然后:
int index = col.indexOf(phone);
col.remove(phone);
col.add(p, index);