Gặp vấn đề với biến static trong java

Chào mọi người. Em có làm 1 bài tập nhỏ đó là làm việc thêm xóa sửa các Slang(ví dụ key là :3 thì nó có value là kute). E có sử dụng thêm java swing. Vì làm việc cùng lúc nhiều class nên biến lưu trữ [key,value] em đặt biến static.
private static Map<String, ArrayList<String>> multiMap = new HashMap<String, ArrayList<String>>();
Em có thao tác đó là thêm 1 dữ liệu slang. Nếu nó trùng thì em sẽ thêm giá trị value vào.
Em nhận thấy. Nếu thêm một slang, đồng nghĩa với việc thêm một cặp [key,value] thì khi em tìm cặp [key,value] đó thì em sẽ tìm được. Em đoán rằng. Do multiMapstatic nhưng do ArrayList không tĩnh nên nếu ta chỉ thay đổi giá trị của arrayList thôi thì khi truy cập ở chỗ khác nó sẽ không được cập nhật. Nên với trường hợp nhập trùng key, em chọn cách xóa key cũ và thêm mới lại.

String[] valueStrings = null;
if(value.length() > 0){
       valueStrings = value.split("[|]");
       for(int i = 0; i <valueStrings.length; i++){
           valueStrings[i] = valueStrings[i].trim();
       }
   }
if(choose == 0){ // 0 nghĩa là thêm mới
   Slang.multiMap.put(NewSlangs, new ArrayList<>());
   Slang.multiMap.get(NewSlangs).addAll(Arrays.asList(valueStrings));
}
else if(choose == 2){ // 2 nghĩa là thêm value 
   ArrayList<String> tempArrayList = new ArrayList<>();// em dang bug nên sửa tạm, mọi 
   //người bỏ qua nhé.
   tempArrayList.addAll(multiMap.get(NewSlangs));
   tempArrayList.addAll(Arrays.asList(valueStrings));
   Slang.multiMap.remove(NewSlangs); 
   Slang.multiMap.put(NewSlangs, tempArrayList);
}

Sau khi gặp lỗi là với thêm mới key,value thì khi tìm lại thì sẽ tìm được. Nhưng với chèn thêm value thì lại không. Nên em debug và có một số vấn đề ở đây.

Khi thêm mới.

image


Địa chỉ ArrayList mà em thêm mới là #1893
Khi tìm lại cặp [Key,Value] này, địa chỉ ArrayList của value cũng là #1893
Và em tìm được.

Nhưng khi thêm value



ArrayList cũ chứa các value cũ có địa chỉ là #2050
Các string nó chứa có các địa chỉ tăng dần là #10177, #10178,...

ArrayList mới chứa các value mới có địa chỉ là #2088

Sau khi addAll thì ArrayList mới này chứa đúng địa chỉ các StringArray cũ đã chứa và chứa thêm địa chỉ của String mới.

Nhưng khi tìm nó thì nó chỉ có chứa 4 value cũ



và địa chỉ của nó cũng khác luôn.

Vậy mọi người cho em hỏi lý do vì sao và cách khắc phục ạ. Em xin cảm ơn

1 Like

Có lời khen cho bạn là bạn đưa ra câu hỏi mô tả rất đầy đủ cho vấn đề của bạn. Điều này rất tốt!


Về vấn đề của bạn gặp phải:

Bạn có nhắc đến địa chỉ (ngầm định là con trỏ)? Trong Java không có khái niệm này! Những con số thể hiện đó có thể chỉ định danh tạm thời mà quá trình Gỡ lỗi của Netbean gắn cho từng thực thể. Bạn có để ý this = (Slang) #.... có thay đổi trong từng hình không? Nó được gán đến 3 giá trị: 1848, 199510295. Chả lẽ 1 thực thể lại chạy lung tung trong bộ nhớ như thế? Đó cũng không phải giá trị băm (hash) của thực thể.
Java, không phải C/C++, thế nên bạn nên bớt chú ý đến các con số bạn cho là địa chỉ đó đi. Bạn chỉ nên chú ý đến giá trị thực sự của thực thể.

Vấn đề tiếp theo, khi tìm lại thì giá trị vừa thêm không có.
Ngoài cách thêm như trên thì bạn có làm bằng cách nào khác không?
Theo tài liệu của HashMap thì mình làm thế này:

ArrayList<String> val = Slang.multiMap.get(NewSlangs);
// ...
val.addAll(Arrays.asList(valueStrings));

Thế là xong!

Mình không nghĩ từ khóa static lại gây ra chuyện này.
Một trường tĩnh có thể gán cho bất kì giá trị nào mà. Bên trong nó có thể là bất kì thực thể nào, chỉ khác là nó tồn tại duy nhất cho 1 lớp, dù tạo nhiều thực thể của lớp đó. Nó chỉ đơn giản là giá trị của lớp, không phải của thực thể.

Còn nếu nó thực sự như vậy, thì lỗi này to lắm, cần báo cho Oracle ngay.

8 Likes

Em cảm ơn đóng góp của anh. Với việc thêm value ở ArrayList em đã thử rất nhiều cách thêm nhưng đều không được ạ. Vẫn không hiểu vụ nếu thêm mới cặp key, value thì lại tìm thấy.

bạn thử up full source code lên git để mn xem sao. Có 1 số lí do khiến cho dữ liệu không đồng bộ có thể là do vấn đề multi threading hoặc bạn dùng sai reference

3 Likes

Cảm ơn anh đã quan tâm. Hiện tại em đã lọc được cái trường hợp khiến nó bị sai. Em có thể chụp ảnh các trường hợp và cho a xem. Nếu các trường hợp đó chưa đủ thì em hẳng up code lên ạ. Tài nhiều file quá.
Thứ nhất là với choose==0 thì có nghĩa là thêm mới một slang. choose == 2 thì có nghĩa là slang đã tồn tại và em muốn thêm giá trị vào ArrayList<String>


Với choose ==0 thì code chạy bình thường.
Với choose ==2 thì có các trường hợp sau. Gỉa dụ em có sẵn cặp [Key, Value][:3, huhu]
Nếu choose == 2 chỉ có 2 câu lệnh trên thì nếu em nhập thêm value[hic]
image
Thì kết quả tìm được chạy đúng:

Nhưng với các trường hợp như sau:
Thêm đơn thuần giá trị value vào mảng ArrayList có sẵn, bằng câu lệnh
Slang.words.get(word).add(meaning);
Kết quả sẽ sai:

Kì lạ ở chỗ nếu em addAll các giá trị value cũ vào một ArrayList tạm, rồi lấy biến tạm đó add tiếp tục vào [key,value] thì lại sai. Nếu dùng vòng lặp for để add các value vào biến tạm đó cũng sẽ sai. Vậy em rút ra đó là nếu lấy bất cứ thứ gì có liên quan đến value cũ. Thì khi thoát hàm add đó. Cặp [key,value] sẽ không bị thay đổi.


Bạn có gọi Slang.words.put() ở nơi nào đó khác ngoài mấy hình bạn đưa rồi. Chỗ đó đã gán ngược về ArrayList trước đó.
:thinking:

3 Likes

Edit: Hình như vấn đề là do các file java form e để ở 1 packet khác. Còn file xử lí logic em để ở packet khác. Nên xử lí có lỗi. Khi em để chung hết thì lại không lỗi nữa. Nếu ai biết được nguyên do vì sao thì giúp em và các bạn khác biết thêm kiến thức nhé.

Em để tất cả cái file chung một packet thì không có lỗi nữa ấy anh. Em chịu :frowning:

chính vì vậy nên mình mới muốn bạn up full code lên do java có 1 khái niệm gọi là class loader, nếu cùng 1 class nhưng khác class loader thì biến static cũng khác nhau.
Hiện với 1 ít code bạn chụp thì vẫn khá khó để tìm ra nguyên nhân do mình vẫn chưa rõ logic binding với GUI và bạn sửa hơi nhiều so với code gốc. Bạn up full code mà bị lỗi lên github hay gì đó để mn vào đọc thì có thể sẽ có câu trả lời thoả đáng nhất cho bạn.

3 Likes

Dạ vâng. Sau khi hoàn thành đồ án này thì em sẽ quay lại vấn đề này ạ

1 Like

Em quay lại rồi đây. Trước tiên là câu xin lỗi của em. Thật tình là do lỗi của em chứ không phải là lỗi của Oracle. Do mới tập làm swing nên em có thêm lệnh readFile mỗi khi quay về màn hình chính. Nên thêm giá trị thì được còn sửa hay xóa thì lại bị cập nhật như cũ do readFile. E xin lỗi vì lm mọi người hiểu lầm. Nhưng vì nhận ra bug đó mà em đã hiểu hơn về các giao diện. Cũng là bài học cho em. Em cảm ơn mọi người.
Link bài tập của mình cho ai cần tham khảo. Dạng bài tập như thư viện.

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?