我正在编写一个代码来保存,删除和加载一个人的身高和体重数据。我创建了两个类:
class Person {
private int height;
private int weight;
public Person(int h, int w) {
height = h;
weight = w;
}
public int getHeight() {
return height;
}
public int getWeight() {
return weight;
}
public String getValues() {
return ("Height "+height+" and weight "+weight);
}
}
class DataModified { //Problem in this class
private LinkedList<Person> lList;
private ListIterator<Person> lIter;
public DataModified() {
lList = new LinkedList<Person>();
lIter = lList.listIterator();
}
public void save(Person p) {
Person p1, p2; //p1: Data needed to be saved
p1 = new Person(p.getHeight(), p.getWeight()); //p2: Data already on the list
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
System.out.println("Person: " + p1.getValues() + " had already been on the list.");
}
else {
lIter.add(p1);
System.out.println("Person: " + p1.getValues() + " is added to the list.");
}
}
public void delete(Person p) {
Person p3, p2; //p3: Data needed to be deleted
p3 = new Person(p.getHeight(), p.getWeight());
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
lIter.remove();
System.out.println("Person: " + p3.getValues() + " is deleted from the list.");
}
else {
System.out.println("Person: " + p3.getValues() + " is not on the list.");
}
}
public void load() { //Problem
lIter = lList.listIterator();
Person p2;
for(int i = 1; lIter.hasNext(); i++){
p2 = lIter.next();
System.out.println("Person "+i+" has "+p2.getValues());
}
}
}
我已经从班级DataModified
测试了这3个方法:我首先保存3个人的数据,然后删除1个人并加载其余的人。但是,最后一种方法不会打印列表中的2个人,而是打印之前删除的人。
我的问题是:
load()
方法的工作方式如此?lIter
。那么lList
和lIter
是相同的列表还是2个单独的列表?如果它们不相同,我如何从lList
?lIter
数据
答案 0 :(得分:2)
正如其他人指出的那样,您的delete
方法肯定存在错误。如上所述,如果在列表中找到目标Person,则将删除列表中的最后一个Person,而不是目标。当你找到这个人并立即将其删除而不是继续循环时,你真的需要能够切断while循环。
回答你的问题:
出了什么问题?删除中删除错误Person的错误。
lList
和lIter
列表相同吗?概念上是,技术上没有。 lList
是列表本身,lIter
是作用于该列表的迭代器。它本身不是一个列表。它是一个迭代器。但它所处理的数据绝对是同一个列表。
如何停止迭代?你有几个选择。目前编写代码的最简单方法是break
语句。它停止执行当前循环并继续在块外执行。在你的添加和删除方法中,在alreadyExist
设置为true后立即断开是有意义的。 jiveturkey首先建议的另一个选项是将alreadyExist
添加为while循环的条件。然后,如果有更多项目要迭代并且alreadyExist
尚未设置为true,那么您只会继续迭代。第三种选择是在找到Person后立即进行实际工作(即删除),然后完全从方法返回。
除此之外,还有一些未经请求的一般建议:)
您在多种方法中比较Person对象。随着时间的推移,这将难以维护,因此最好在一个地方定义比较。 Java为此提供了equals
方法。它位于每个Object
中,但默认实现不会帮助您,因此您希望覆盖它。在您的情况下,如果它们的高度和权重相等,则认为两个不同的Person对象在概念上是相等的。因此,如果高度和重量相等,则覆盖Person中的equals()方法以返回true。有关提示,请参阅How to override equals method in java或http://users.csc.calpoly.edu/~gfisher/classes/102/info/howToOverrideEquals.html。如果您覆盖equals
,则还需要覆盖hashCode
。
您正在复制Person参数。传入的确切对象不是从列表中添加或删除的实际对象;副本是。你可以使用paremeter。在最好的情况下,您目前有不必要的性能损失(创建额外的对象)。在最糟糕的情况下,你会遇到错误。
lIter
在构造函数和每个方法中都设置。如果您不需要跨方法调用存储其当前状态,那么它应该只是一个局部变量,用于方法然后丢弃。
getValues()
目前仅用于使对象具有人类可读性。这是一个常见问题,也是toString()
的任务,也在Object
中定义,并且在您编写的任何类中都可以覆盖。您需要做的就是将getValues
重命名为toString
。然后你可以直接在日志消息中使用它。以下示例。
这是我如何重写删除,假设equals
中的Person
方法很好,getValues
重命名为toString
:
public void delete(Person p) {
boolean alreadyExist = false;
ListIterator definitelyNotLIter = lList.listIterator();
while(definitelyNotLIter.hasNext()) {
Person current = definitelyNotLIter.next();
if (p.equals(current)) {
alreadyExist = true;
definitelyNotLIter.remove();
// Option 1:
break; // next line to execute will be the if(alreadyExist) block
// Option 2:
// put your successful delete logging here
// return;
// and leave the failed delete logging outside the loop
// Option 3:
// Do nothing. The looping will continue, and you'd have a deleteAll method, where multiple items would get deleted if you managed to get duplicates in the list.
// You actually wouldn't need alreadyExist any more.
// I'd go with option 1, myself
}
}
if(alreadyExist) {
System.out.println("Person: " + p + " is deleted from the list."); // p.toString() will get called
}
else {
System.out.println("Person: " + p + " is not on the list."); // p.toString() will get called
}
}
答案 1 :(得分:1)
在delete()
中,一旦找到了您的个人,就会在第一次找到某人并继续前进时将alreadyExist
设置为true
。因此,一旦设置好,它就会为每个人设置。如果您在位置1的列表中找到您的人员,则您将删除他,但之后您将删除下一个人,依此类推。你所有的while循环都需要说。
while (!alreadyExists && lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
lIter.remove();
}
}
// Delete the if/else code
你应该摆脱成员变量:
private ListIterator<Person> lIter;
答案 2 :(得分:0)
问题在于您的delete
方法:
在删除任何内容之前,您将遍历整个列表。 ListIterator.remove
only deletes the last item returned by next()
。当您找到已存在的项目时,您需要中断:
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
break;
}
}
此外,您要比较Person
对象的方式应该采用equals()
方法,described here。
最后,您在这里完全没有必要创建/使用与参数Person
重复的额外p
。只需使用p
代替p1
(save
}和p3
(delete
)。
答案 3 :(得分:0)
void remove()从列表中删除返回的 最后 元素 by next()或previous()
但当您到达所需的Person
对象时,您会继续迭代下一个 Person
对象。
找到目标对象后,您需要 break
while
循环。
if ((p2.getHeight()==p3.getHeight())&&(p2.getWeight()==p3.getWeight())){
alreadyExist = true;
break;
}
现在最后一个元素是必需的对象,现在可以使用remove()
。
if(alreadyExist) {lIter.remove();}