【问题标题】:indexOf always returns -1 [duplicate]indexOf 总是返回-1 [重复]
【发布时间】:2017-01-22 14:21:10
【问题描述】:

我有一个对象 User 的数组列表,其中包含用户的用户名和密码。我创建了一个updateUsername 方法来尝试更改用户的用户名,在其中我使用了indexOf,但它总是返回-1(它在数组列表中找不到所述用户)。

updateUsername 方法:

public void updateUsername(User user, String username) {
    ArrayList<User> users = getAllUsers();
    int i = users.indexOf(user);
    user.setUsername(username);
    users.set(i,user);
    synToFile(users);
}

当一个按钮被点击时,这个方法在控制器中被调用:

public JFXListView<Label> lview2;

@FXML
void changeUsername(ActionEvent event) {
    String username = newUserField.getText();
    UserDAO theDAO = new UserDAO();
    Label lbl = lview2.getSelectionModel().getSelectedItem();
    //the items in the listview are of object label
    User u = theDAO.getUser(lbl.getText());
    theDAO.updateUsername(u,username);
    ObservableList<Label> userList = theDAO.storeUsers();
    lview2.setItems(userList);
}

lview2 是单独控制器中的列表视图 - 我已在单独控制器中实例化:

changeUsernameController cu = (changeUsernameController)fxmlLoader.getController();
cu.lview2 = listView;

不认为这些是必要的,但我在这里也添加了getAllUsers()synToFile()getUser() 方法:

public ArrayList<User> getAllUsers() {
    Scanner sc;
    String record = null;
    String[] fields;
    ArrayList<User> users = new ArrayList<User>();

    try {
        sc = new Scanner(dataFile);
        while (sc.hasNextLine()) {
            record = sc.nextLine();
            fields = record.split(";");
            String username = fields[0];
            String password = fields[1];
            User u = new User();
            u.setPassword(password);
            u.setUsername(username);
            users.add(u);
        }
    } catch (FileNotFoundException e) {
        System.out.println("No record found!");
        //e.printStackTrace();
    }
    return users;
}

public void synToFile(ArrayList<User> userList) {
    if (userList == null) {
        return;
    }

    try {
        FileWriter out = new FileWriter(dataFile);
        for (User u: userList) {
            out.append(u.toString() + "\n");
        }
        out.close();
    }catch (IOException e) {
        e.printStackTrace();
    }
}

public User getUser(String username) {
    ArrayList<User> users = getAllUsers();
    User user = null;
    for (User u: users) {
        if (u.getUsername().equals(username)) {
            user = u;
            break;
        }
    }
    return user;
}

注意:我在 updateUsername() 方法中添加了调试行 - ArrayList 应该是这样,并且用户对象也是正确的。

用户等级:

package Server;

import java.util.ArrayList;


public class User {

private String username;
private String password;
private ArrayList<Double> scoreList=new ArrayList<Double>();

public User() {

}


public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String toString() {
    return username + ";" + password;
}

public String usernameString() {
    return username;
}
}

【问题讨论】:

  • 请显示用户类。你了解 indexOf 是如何找到索引的吗?
  • 您是否在 User 类中覆盖了 equals
  • indexOf 使用equals(Object),你能告诉我们它的代码吗?
  • 如果不覆盖equals,两个对象只有当它们是同一个对象时才是equals
  • indexOf 的 JavaDoc 是公开的,因此您应该阅读它以了解它的工作原理以及需要做什么才能正确使用它。当您不知道如何实现equals 时,您为什么不对此进行研究呢?你不是第一个在 SO 上问这个问题的人。

标签: java listview arraylist


【解决方案1】:

您应该覆盖User 类中的equals 方法。 indexOf 方法内部使用equals 来查看数组中的每个元素是否等于输入参数。

有关如何在 Java 中覆盖 equals,请参阅 this 答案。

【讨论】:

  • 我应该如何覆盖它?
【解决方案2】:

这是 User 类的工作版本:

public class User {

private String username;
private String password;
private ArrayList<Double> scoreList=new ArrayList<Double>();

public User() {

}


public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String toString() {
    return username + ";" + password;
}

public String usernameString() {
    return username;
}
@Override
    public boolean equals(Object obj) {
        if (obj instanceof User){
            User tmp = (User)obj;
            return tmp.getUsername().equals(getUsername());
        }
        return false;
    }

}

我在equals()方法中只添加了对用户名的测试,但您也可以根据您的要求添加其他测试。

【讨论】:

    【解决方案3】:

    除非你覆盖equals,否则两个对象只有在它们是同一个对象时才相等。在您的情况下,您假设它们具有相同的username。更好的方法是使用 Map 而不是列表,并使用 String 作为 Key,尽管这会使 User 类变得多余。

    // Username to password
    public Map<String, String> getAllUsers() {
        try (Stream stream = Files.lines(datafilePath)) {
           return stream
                  .map(line -> line.split(";"))
                  .collect(Collectors.toMap(l -> l[0], l -> l[1]));
    }
    
    // to update the user
    Map<String, String> userToPasswordMap = getAllUsers();
    String password = userToPasswordMap.remove(oldUsername);
    if (password == null) // error
    userToPasswordMap.put(newUsername, password);
    syncToFile(userToPasswordMap);
    

    【讨论】:

      【解决方案4】:

      IndexOf 方法使用 equals 来验证列表中是否存在对象...

      所以您的 USER 类必须正确覆盖该方法(hascode 也是)

      这就是为什么返回的索引是 -1 的原因,即使用户对象在列表中..

      这里是实现

      229     public int indexOf(Object o) {
      230         if (o == null) {
      231             for (int i = 0; i < size; i++)
      232                 if (elementData[i]==null)
      233                     return i;
      234         } else {
      235             for (int i = 0; i < size; i++)
      236                 if (o.equals(elementData[i]))
      237                     return i;
      238         }
      239         return -1;
      240     }
      

      refernce

      【讨论】:

      • 哈希码也是???
      • Hashcode 仅在相等性检查中有用,indexOf 不使用
      • @Tom 请在这里取implements的英文意思:)
      • 请参考本书中的java最佳实践joshua bloch Effective java
      • @CKing 如果您评论 Java 代码,这并不意味着它应该在他通常在 Java 中的含义之外使用。这只会造成混淆或误解。
      【解决方案5】:

      您需要覆盖用户类中的等号,以便它在 indexOf() 方法中工作(如 cmets 中所述)。

      一个例子是。

              public class User {
              String username;
              String password;
      
              @Override
              public boolean equals(Object obj) {
                  if (obj == null) {
                      return false;
                  }
                  if (!User.class.isAssignableFrom(obj.getClass())) {
                      return false;
                  }
      
                  final User other = (User) obj;
      
                  if ((this.username == null) ? (other.username != null) : !this.username.equals(other.username)) {
                      return false;
                  }
                  if (!this.password.equals(other.password)) {
                      return false;
                  }
                  return true;
              }
          }
      

      正如评论中所说,IndexOf() 不使用哈希码,我知道这与问题无关,但是覆盖这两种方法(等于和哈希码)是惯例,因为你会遇到其他问题HashMap 或 HashSet 等类,如果你不覆盖它的话。

      【讨论】:

      • 注意:indexOf 不使用hashCode()
      • 感谢您的澄清。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多