我有一個抽象的 Database 類,它實作了 Serializable 并有 2 種讀/寫.ser檔案的方法。資料庫子項的一個示例是CredentialsUsers擴展Database并且具有Hashmap<Credentials,User>. 當我打開我的應用程式時,我加載資料,read完成后我將資料保存為load. 我的應用程式中支持的用戶型別之一是具有特殊權限的管理員。在我運行我的應用程式之前,我確保使用initAdmin()下面的初始化一個管理員。管理員可以檢查用戶數量等統計資訊。如果rm *.ser我的檔案和運行應用程式一切順利,但每次我運行它時,我都會在其中添加一個重復的管理員Hashmap. 我已經使用了 2 個小時,添加了沒有意義的特殊檢查(添加密鑰,僅在地圖中不存在時才對等),但我仍然找不到資料庫允許重復值的原因。有任何想法嗎?下面是一些關于讀/寫的代碼(抽象資料庫的方法):
public Object read() {
Object obj = null;
try {
File temp = new File(this.filename);
temp.createNewFile(); // create file if not present
FileInputStream fileIn = new FileInputStream(this.filename);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
obj = objectIn.readObject();
objectIn.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
public void write() {
try {
File temp = new File(this.filename);
temp.createNewFile(); // create file if not present
FileOutputStream fileOut = new FileOutputStream(this.filename);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(this);
objectOut.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
這是 Admin init:
private void initAdmin() throws NoSuchAlgorithmException {
Admin admin = new Admin(new Credentials("Edward", "password"),
"Edward", 25, "[email protected]", Gender.MALE, "fakephone");
if(credentialsUserDatabase.selectUser(admin.getCredentials())==null)//entry not found
credentialsUserDatabase.insertUser(admin.getCredentials(), admin);
}
最后是實作:
public class CredentialsUser extends Database {
@Serial
private static final long serialVersionUID = 0;
private HashMap<String, User> users; //Mapping of hash(Credentials) -> User
public void insertUser(Credentials credentials, User user) throws NoSuchAlgorithmException {
if (user == null || credentials == null)
return;
String hash = Encryption.SHA_512(credentials.toString()); //get credentials hash in a String format
if (!users.containsKey(hash))
users.put(hash, user);
}
你可以在任何地方看到關于重復鍵的無用檢查,也可能是我從檔案中讀取資料庫的方式與它有關。這是可能是問題的最后一部分:
private void loadData(){
Object temp = credentialsUserDatabase.read();
if (temp != null) //EOF returns null
credentialsUserDatabase = (CredentialsUser) temp;
}
方法順序是 loadData()->initAdmin()->Application Runs->write()
uj5u.com熱心網友回復:
您期望具有相同引數的toString兩個實體的方法結果Credentials相同,但事實并非如此。
String hash = Encryption.SHA_512(credentials.toString()); //get credentials hash in a String format
if (!users.containsKey(hash))
users.put(hash, user);
credentials.toString() 將包含新創建的實體的哈希 new Credentials("Edward", "password")
默認情況下,該hashCode方法確實為不同的物件回傳不同的整數。這通常是通過將物件的內部地址轉換為整數來實作的(請參閱此處的檔案)
默認情況下,該toString方法回傳物件類的名稱及其哈希碼(請參閱此處的檔案)。
getClass().getName() '@' Integer.toHexString(hashCode())
因此,當您計算哈希時,每個新實體都會有所不同。
您可以通過創建多個具有相同引數值的新 Credentials 實體來確保它。
Credentials instance1 = new Credentials("Edward", "password");
Credentials instance2 = new Credentials("Edward", "password");
Console.out.println(instance1.toString());
Console.out.println(instance2.toString());
要解決這個問題,您需要覆寫類中的equals和hash方法Credentials,因此具有相同引數的兩個實體將回傳相同的哈希值。在這種情況下,它們的鍵將是相等的,并且您不會得到重復項。
您可以在相關答案中閱讀有關如何執行此操作以及為什么需要執行此操作的資訊:
- https://stackoverflow.com/a/27609/4671372
- https://stackoverflow.com/a/2265637/4671372
- https://stackoverflow.com/a/38559684/4671372
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/369294.html
上一篇:Java按名稱和擴展名過濾檔案
