Map هي بنية بيانات لتخزين أزواج المفتاح والقيمة.
وهي مشابهة للقواميس في لغات البرمجة الأخرى.
وتحدد واجهة Map العمليات التي يمكنك إجراؤها على Map.
HashMapتحتوي Java على عدد من تطبيقات Map المختلفة.
ويُعد HashMap من أكثرها استخدامًا.
// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
عند تعريف متغير من نوع Map، يُوصى بتعريف المتغير بنوع Map بدلًا من النوع المحدد، كما في المثال أعلاه.
تسهّل هذه الممارسة تغيير تطبيق Map لاحقًا.
كما أن لـ HashMap مُنشئ نسخ.
// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);
أضف مدخلات إلى Map باستخدام put.
fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }
يمكن ربط قيمة واحدة فقط بكل مفتاح.
استدعاء put بالمفتاح نفسه سيحدّث قيمة ذلك المفتاح.
fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }
استخدم get للحصول على قيمة مفتاح ما.
fruitPrices.get("apple"); // => 100
استخدم containsKey للتحقق مما إذا كانت Map تحتوي على مفتاح معين.
fruitPrices.containsKey("apple"); // => true
fruitPrices.containsKey("orange"); // => false
أزل المدخلات باستخدام remove.
fruitPrices.put("plum", 90); // Add plum to map
fruitPrices.remove("plum"); // Removes plum from map
تُرجع طريقة size عدد المدخلات.
fruitPrices.size(); // Returns 2
يمكنك استخدام طريقتَي keySet أو values للحصول على المفاتيح أو القيم في Map على هيئة Set أو collection على الترتيب.
fruitPrices.keySet(); // Returns "apple" and "pear" in a set
fruitPrices.values(); // Returns 100 and 80, in a Collection
HashMap لـ hashCode و equals
يستخدم HashMap طريقتي hashCode و equals الخاصة بالكائن لتحديد مكان تخزين القيم وكيفية استرجاعها لمفتاح معين.
ولهذا السبب، من المهم ألا تتغيّر القيم التي تُرجعانها بين التخزين والاسترجاع، وإلا فقد لا يتمكن HashMap من العثور على القيمة.
على سبيل المثال، لنفترض أن لدينا الصنف التالي الذي سيُستخدم مفتاحًا في Map:
public class Stock {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
return Objects.equals(name, other.name);
}
return false;
}
}
تعتمد hashCode و equals على الحقل name، الذي يمكن تغييره عبر setName.
قد يؤدي تغيير hashCode إلى نتائج مفاجئة:
Stock stock = new Stock();
stock.setName("Beanies");
Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);
stockCount.get(stock); // Returns 80
Stock other = new Stock();
other.setName("Beanies");
stockCount.get(other); // Returns 80 because "other" and "stock" are equal
stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed
stockCount.get(other); // Also returns null because "other" and "stock" are not equal
stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again
stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal
Map.of و Map.copyOf
من الطرق الشائعة الأخرى لإنشاء Map استخدام Map.of أو Map.ofEntries.
// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);
// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
Map.entry("Mon", 30),
Map.entry("Tue", 28),
Map.entry("Wed", 32)
);
وعلى عكس HashMap، فإنها تملأ Map مسبقًا وتصبح للقراءة فقط بمجرد إنشائها.
وتنشئ Map.copyOf نسخة للقراءة فقط من Map.
Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);
يؤدي استدعاء طرق مثل put أو remove أو clear إلى ظهور UnsupportedOperationException.