Không có sự khác biệt giữa các vật thể; bạn có một số HashMap<String, Object>
trong cả hai trường hợp. Có sự khác biệt trong giao diện bạn phải đối tượng. Trong trường hợp đầu tiên, giao diện là HashMap<String, Object>
, trong khi giao diện thứ hai là Map<String, Object>
. Nhưng đối tượng cơ bản là như nhau.
Lợi thế khi sử dụng Map<String, Object>
là bạn có thể thay đổi đối tượng bên dưới thành một loại bản đồ khác mà không vi phạm hợp đồng của bạn với bất kỳ mã nào đang sử dụng nó. Nếu bạn khai báo là HashMap<String, Object>
, bạn phải thay đổi hợp đồng của mình nếu bạn muốn thay đổi triển khai cơ bản.
Ví dụ: Giả sử tôi viết lớp này:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Lớp có một vài bản đồ nội bộ của STRING-> đối tượng mà nó chia sẻ (thông qua các phương pháp accessor) với các lớp con. Hãy nói rằng tôi viết nó với HashMap
s để bắt đầu bởi vì tôi nghĩ rằng đó là cấu trúc thích hợp để sử dụng khi viết lớp.
Sau đó, Mary viết mã phân lớp nó. Cô ấy có một cái gì đó cô ấy cần phải làm gì với cả hai things
và moreThings
, tự nhiên đến nỗi cô đặt rằng trong một phương pháp phổ biến, và cô sử dụng cùng loại tôi sử dụng trên getThings
/getMoreThings
khi xác định các phương pháp của mình:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Sau đó, tôi quyết định rằng thực sự, sẽ tốt hơn nếu tôi sử dụng TreeMap
thay vì HashMap
trong Foo
. Tôi cập nhật Foo
, thay đổi HashMap
thành TreeMap
. Bây giờ, SpecialFoo
không biên dịch nữa, bởi vì tôi đã phá vỡ hợp đồng: Foo
được sử dụng để nói nó được cung cấp HashMap
s, nhưng bây giờ nó cung cấp TreeMaps
thay thế. Vì vậy, chúng tôi phải sửa chữa SpecialFoo
ngay bây giờ (và loại điều này có thể gợn sóng thông qua một codebase).
Trừ khi tôi đã có một lý do thực sự tốt để chia sẻ rằng việc thực hiện của tôi đã sử dụng một HashMap
(và điều đó không xảy ra), những gì tôi nên làm là tuyên bố getThings
và getMoreThings
như chỉ trở Map<String, Object>
mà không bị bất kỳ cụ thể hơn đó.Trong thực tế, ngăn cản một lý do chính đáng để làm cái gì khác, ngay cả trong Foo
tôi có lẽ nên tuyên bố things
và moreThings
như Map
, không HashMap
/TreeMap
:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Lưu ý làm thế nào tôi hiện nay đang sử dụng Map<String, Object>
ở khắp mọi nơi tôi có thể, chỉ được cụ thể khi tôi tạo các đối tượng thực tế.
Nếu tôi đã làm điều đó, sau đó Mary sẽ đã làm điều này:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... và thay đổi Foo
sẽ không làm SpecialFoo
dừng biên dịch.
Giao diện (và các lớp cơ sở) cho phép chúng tôi tiết lộ chỉ với số lượng cần thiết, giữ tính linh hoạt của chúng tôi trong phạm vi để thực hiện thay đổi khi thích hợp. Nói chung, chúng tôi muốn có tài liệu tham khảo của chúng tôi càng cơ bản càng tốt. Nếu chúng tôi không cần biết đó là số HashMap
, chỉ cần gọi số đó là Map
.
Đây không phải là quy tắc mù, nhưng nói chung, mã hóa cho giao diện chung nhất sẽ kém giòn hơn so với mã hóa cho một cái gì đó cụ thể hơn. Nếu tôi nhớ điều đó, tôi sẽ không tạo ra một số Foo
để đặt Mary cho thất bại với SpecialFoo
. Nếu Mary đã nhớ rằng, sau đó mặc dù tôi đã nhầm Foo
, cô ấy đã tuyên bố phương thức riêng của mình với Map
thay vì HashMap
và hợp đồng của tôi thay đổi Foo
sẽ không ảnh hưởng đến mã của cô ấy.
Đôi khi bạn không thể làm điều đó, đôi khi bạn phải cụ thể. Nhưng trừ khi bạn có một lý do để được, err đối với giao diện ít cụ thể.
do đó sự khác biệt duy nhất là khi tôi chuyển nó như một tham số ví dụ sau đó tôi cần tham chiếu một như Bản đồ và khác như HashMap nhưng chúng thực sự là cùng một loại đối tượng chính xác? –
sepiroth
Vâng, chúng là đối tượng chính xác, đó là về hợp đồng * mà bạn đang tạo bằng bất kỳ mã nào sử dụng nó.Tôi đã cập nhật câu trả lời một chút để làm rõ. –
ah, do đó, sự khác biệt là nói chung, Bản đồ có một số phương pháp liên kết với nó. nhưng có nhiều cách khác nhau hoặc tạo bản đồ, chẳng hạn như HashMap và những cách khác nhau này cung cấp các phương thức duy nhất mà không phải tất cả các bản đồ đều có. Vì vậy, nếu tôi sử dụng Bản đồ, tôi chỉ có thể sử dụng các phương pháp Bản đồ, nhưng tôi có một HashMap bên dưới để bất kỳ lợi ích tốc độ, lợi ích tìm kiếm, vv của HashMap sẽ được nhìn thấy trong Bản đồ. Và nếu tôi sử dụng HashMap, tôi có thể sử dụng những phương thức cụ thể HashMap đó và nếu cuối cùng tôi cần phải thay đổi loại bản đồ thì sẽ có nhiều công việc hơn. – sepiroth