Nhận dạng đối tượng và tính tương tác


8

Tôi đã đọc một đề xuất cho các loại giá trị trong Java và tôi đã bắt gặp câu này: "Nhận dạng đối tượng chỉ phục vụ cho khả năng biến đổi, trong đó trạng thái của một đối tượng có thể bị thay đổi nhưng vẫn giữ nguyên đối tượng bên trong."

Theo những gì tôi hiểu (mặc dù có dự kiến), nhận dạng đối tượng là ý tưởng về biến của bạn đóng vai trò là con trỏ hoặc tham chiếu đến một đối tượng nằm ở nơi khác trong bộ nhớ (chẳng hạn như các đối tượng được khởi tạo trên heap trong Java hoặc C #). Vì vậy, điều này sẽ có liên quan gì đến tính biến đổi đối tượng? Có phải điều này ngụ ý rằng, ví dụ, các đối tượng được khởi tạo trên ngăn xếp trong C ++ là bất biến? Tôi gặp khó khăn khi nhìn thấy liên kết ở đây.


"Điều này có nghĩa là ví dụ, các đối tượng được khởi tạo trên ngăn xếp trong C ++ là bất biến" Tôi nghĩ điều làm cho một đối tượng là bất biến là cách đối tượng được thiết kế và những gì nó cho phép, không phải là nơi nó được khởi tạo hoặc nhận dạng của nó. Bạn nghĩ sao?
jordan

Có một diễn đàn thảo luận liên quan đến đề xuất đó? Tôi muốn đề xuất rằng một loại giá trị nên được coi là một loạt các biến được liên kết với nhau bằng băng keo. Cho struct Point {public int x,y;}, một khai báo Point ptnên khai báo hiệu quả hai biến được gọi pt.xpt.y. Một tham số phương thức của loại Pointnên là hai inttham số. Theo các quy tắc như vậy, các khía cạnh duy nhất sẽ yêu cầu bất kỳ thay đổi nào trong Thời gian chạy sẽ là các mảng và các giá trị trả về của hàm. Mảng chỉ chứa nguyên thủy hoặc chỉ vật thể có thể được xử lý ...
supercat

... bằng cách sử dụng mảng nguyên thủy hoặc mảng đối tượng và các phần tử xen kẽ. Mảng chứa hỗn hợp nguyên thủy và giá trị có thể được cung cấp dưới dạng một mảng các đối tượng, mục đầu tiên trong đó là tham chiếu đến một mảng các giá trị. Nếu số lượng đối tượng hoặc nguyên thủy trong cấu trúc bị hạn chế, trả về hàm có thể được xử lý mà không thay đổi thời gian chạy, bằng cách thêm thành viên Threadđể giữ chúng.
supercat

1
@supercat theo cách JCP hoạt động, nếu ai đó muốn nó bằng ngôn ngữ cốt lõi và hét to đến mức "Java đã chết nếu không hiểu điều này" thì nó sẽ được đưa vào.
jwenting

Bạn có thể thấy bài viết này hữu ích, về chính chủ đề này: Các đối tượng nên bất biến
yegor256

Câu trả lời:


10

Trước khi giải quyết danh tính, hãy xác định ý nghĩa của chúng ta bằng cách bình đẳng chính xác hơn một chút. Chúng tôi nói hai điều là bằng nhau khi và chỉ khi chúng tôi không thể phân biệt chúng (xem: Danh tính của những người không hiểu biết ). Điều đó có nghĩa là việc hai thứ có bằng nhau hay không phụ thuộc vào phương tiện chúng ta phải kiểm tra chúng.

Chúng ta hãy nghĩ về điều đó nhiều hơn trong các điều khoản lập trình. Chúng ta hãy để những định kiến ​​của chúng ta ở cửa và giả sử chúng ta đang làm việc trong một ngôn ngữ hoàn toàn mới, trong đó tất cả các biến và giá trị là bất biến. Theo định nghĩa ở trên, hai giá trị ABbằng nhau khi và chỉ khi không có chương trình nào trong ngôn ngữ mang lại kết quả khác nhau khi Ađược sử dụng thay thế Bhoặc ngược lại. Giả sử ABlà (IEEE 754) nổi và khi được thay thế vào biểu thức _ + 1.0, kết quả là 1.0cho cả hai AB. Chắc chắn ABđều bằng không. Họ có bằng nhau không? Điều đó phụ thuộc - ngôn ngữ có cung cấp bất kỳ chức năng nào cho phép tôi xác định dấu của số không? Nếu không, chúng bằng nhau; nếu có, họ có thể không.

Vì vậy, hai giá trị bằng nhau bất cứ khi nào chúng cho cùng một kết quả cho tất cả các kết hợp hoạt động có thể có mà chúng hỗ trợ. Các giá trị bất biến nói riêng không tạo ra các kết quả khác nhau tùy thuộc vào hoạt động nào trước đây được áp dụng cho chúng. Vì lý do đó, chúng tôi không quan tâm nếu hai biến chỉ đến hai bản sao có cùng giá trị hoặc nếu cả hai đều trỏ đến cùng một bản sao.

Điều này có liên quan gì đến tính đột biến? Khả năng tương tác ngụ ý ngôn ngữ của chúng ta có một số khái niệm về một ô nhớ có nội dung có thể bị ghi đè. Giả sử chúng ta thêm hỗ trợ cho các ô nhớ có thể thay đổi vào ngôn ngữ của mình:

  • ref <value>tạo một ô nhớ mới , khác biệt với tất cả các ô khác, được khởi tạo <value>.
  • <variable> := <value> ghi đè lên nội dung của một ô tham chiếu.
  • !<variable> trả về giá trị hiện được lưu trữ trong một ô tham chiếu.

Bây giờ hãy nghĩ về sự bình đẳng có nghĩa là gì đối với các ô nhớ. Giả sử A = ref 0B = A. Hãy xem xét chương trình này:

A := 1
print(!_)

Thay thế trống cho Abản in 1, và thay thế cho Bbản in 1là tốt. Bây giờ giả sử A = ref 0B = ref 0. Trong trường hợp này, thay thế vào chương trình in trên 10, kể từ bây giờ ABtrỏ đến các ô nhớ khác biệt.

Vì vậy, vấn đề đối với chúng ta là hai tham chiếu trỏ đến cùng một ô nhớ hay các ô nhớ khác nhau. Vì vấn đề đó, sẽ rất hữu ích khi có một cách hiệu quả và chung để phân biệt hai tài liệu tham khảo. Phương pháp hiện tại của chúng tôi để so sánh các giá trị họ nắm giữ và nếu chúng biến đổi bằng nhau thì một trong số chúng gây rắc rối vì một số lý do:

  • Nó phụ thuộc vào việc có thể so sánh các giá trị được lưu trữ trong các ô nhớ cho sự bằng nhau. Bình đẳng không có ý nghĩa đối với tất cả các loại - ví dụ, nói chung, nó vô nghĩa đối với các hàm, bởi vì không có phương pháp chung nào để xác định xem hai hàm chưa biết có bằng nhau hay không (điều này đang xâm nhập vào lãnh thổ Vấn đề). Vì vậy, đưa ra hai tham chiếu đến các hàm lưu trữ các ô nhớ, chúng ta không thể so sánh các hàm mà chúng giữ cho bằng nhau.
  • Nó phụ thuộc vào việc có một số giá trị mà chúng ta có thể gán cho một trong hai tham chiếu. Vì vậy, ngay cả khi sự bình đẳng có ý nghĩa đối với tất cả các loại trong ngôn ngữ, chúng ta vẫn cần quyền truy cập vào một giá trị cho từng loại mà chúng ta muốn so sánh. Điều gì xảy ra nếu xây dựng một giá trị của loại đó có tác dụng phụ?
  • Giá trị tham chiếu mà chúng ta sử dụng để thay đổi một trong các tham chiếu phải khác với giá trị mà ô nhớ đã có, vì vậy chúng ta thực sự cần hai giá trị.
  • Mã để so sánh các tham chiếu của các loại khác nhau sẽ trông chính xác cùng một lưu cho hai giá trị chúng tôi sử dụng.
  • Chúng tôi cần sao lưu và khôi phục giá trị của tài liệu tham khảo mà chúng tôi thay đổi để tránh thay đổi ý nghĩa của chương trình.

Vì vậy, sẽ hữu ích cho ngôn ngữ khi cung cấp một thao tác để kiểm tra trực tiếp nếu hai tham chiếu trỏ đến cùng một ô nhớ có thể thay đổi. Hàm như vậy là vô nghĩa đối với các giá trị bất biến; Trên thực tế, tôi muốn nói rằng nó hoàn toàn có hại. Nếu có một cách để biết liệu hai 1s được lưu trữ ở những nơi khác nhau trong bộ nhớ, thì có thể có các chương trình quan tâm liệu tôi có vượt qua cái này 1hay cái kia không. Tôi thực sự không muốn lo lắng về việc liệu tôi có "quyền 1" hay không; toán học là đủ khó như nó là! Vì vậy, rõ ràng rằng việc có thể kiểm tra sự bình đẳng bộ nhớ chủ yếu hữu ích cho các loại có thể thay đổi.


5

Hình ảnh bạn có hai đối tượng ví dụ cho các thể hiện của lớp List. Cả hai danh sách có cùng một nội dung. Bây giờ bạn đang đọc danh sách và tính toán và xuất ra một cái gì đó dựa trên nội dung của chúng. Có vấn đề gì danh sách bạn sử dụng? Không phải vì chúng có cùng nội dung.

Nhưng nếu một trong những danh sách bị thay đổi thì sao? Bây giờ nó không thành vấn đề mà bạn chọn để đọc và xuất ra một cái gì đó. Do đó, bạn cần có khả năng phân biệt giữa chúng và bạn muốn ngay cả trong một số tình huống có thể kiểm tra xem hai biến có trỏ đến cùng một đối tượng không (hoặc danh sách ở đây).

Tuy nhiên, nếu bạn không thể thay đổi nội dung của danh sách thì bạn thậm chí không cần phải có hai đối tượng danh sách có cùng nội dung vì dù sao bạn cũng không thể thay đổi chúng. Nếu bạn muốn "thay đổi" nội dung, thay vào đó bạn sẽ tạo một đối tượng danh sách mới với nội dung khác - như tôi đã nói một đối tượng mới. Vì vậy, từ quan điểm này, bản sắc không thành vấn đề. Chỉ nội dung mới và chỉ nên sử dụng nội dung để so sánh hai danh sách.

Cũng lưu ý rằng trình biên dịch có thể trỏ đến cùng một đối tượng danh sách ngay cả khi bạn khai báo hai đối tượng vì nó chỉ cần lưu trữ nội dung của nó một lần vì nó không thể thay đổi.


0

Nhận dạng đối tượng không tồn tại "chỉ" để hỗ trợ khả năng biến đổi, nhưng cũng có những cách sử dụng khác [thực sự, một thể hiện của Objectloại chỉ hữu ích như một mã thông báo nhận dạng, vì nó không có thuộc tính có thể thay đổi có thể quan sát được!] Thay vào đó, nhận dạng thường là - đặc điểm được nêu ra là một đối tượng có thể thay đổi sẽ có được bất cứ lúc nào tồn tại nhiều tham chiếu đến đối tượng, chúng không phải là tất cả được kiểm soát bởi một chủ sở hữu và các thực thể bên ngoài chủ sở hữu có thể - không có kiến ​​thức của chủ sở hữu - thực hiện hoặc thấy các thay đổi đối với đối tượng đó .

Giả sử rằng một số trường tĩnh Xgiữ tham chiếu đến phiên bản phần tử đơn của int[]và X [0] = 5. Trường tĩnh Ycũng giữ một phần tử cho một thể hiện phần tử đơn int[]và Y [0] = 5. Nếu mã bao giờ gọi IdentityHashCase()trên XY, hoặc nếu các xét nghiệm đang X==Y, nó sẽ có thể để phân biệt xem XYxác định các trường hợp tương tự int[]hoặc các trường hợp khác nhau. Tương tự như vậy, nếu mã làm một cái gì đó giống như X[0]+=1; Y[0]+=2;, hành vi sẽ phụ thuộc vào việc XYxác định cùng một thể hiện hoặc các thể hiện khác nhau. Tuy nhiên, nếu mã không bao giờ kiểm tra XYrõ ràng cho sự bình đẳng tham chiếu, cũng không kiểm tra mã băm nhận dạng của chúng hoặc thực hiện bất kỳ điều gì khác "liên quan đến tham chiếu" và nếu X[0]Y[0]không bao giờ được sửa đổi, sau đó XYsẽ tương đương bất kể họ xác định cùng một mảng hoặc các mảng khác nhau.

Một trong những điều khó chịu về danh tính trong Java hoặc .NET là nhận dạng của một đối tượng về cơ bản phụ thuộc vào nơi ở của mọi thực thể trong vũ trụ có thể tạo ra hoặc nhìn thấy những thay đổi đối với đối tượng đó. Nếu một tham chiếu đến một đối tượng được tự do tiếp xúc với mã bên ngoài, chủ sở hữu của đối tượng sẽ mất quyền kiểm soát đối với nó và không bao giờ có thể lấy lại được.

Các loại giá trị, không giống như các đối tượng, không bao giờ có thể được quan sát hoặc sửa đổi ngoại trừ bởi đối tượng hoặc phương thức trong đó chúng được khai báo. Do đó, một đối tượng chứa trường loại giá trị không phải lo lắng về việc mất quyền kiểm soát đối với trường đó, vì điều đó không thể xảy ra về mặt ngữ nghĩa. Trong .NET (mặc dù không phải Java), có thể chuyển một biến, trường, phần tử mảng hoặc vị trí lưu trữ khác làm "tham số tham chiếu". Làm như vậy sẽ tạm thời cho phép phương thức quan sát hoặc sửa đổi nội dung của vị trí lưu trữ đã qua trong thời gian thực hiện, nhưng bất kỳ "byref" nào (thuật ngữ kỹ thuật cho những gì được thông qua) đều được đảm bảo bị hủy trước khi phương thức trở lại, do đó đảm bảo rằng người gọi duy trì quyền kiểm soát dữ liệu được giữ trong đó,danh tính không mong muốn .


Trong Java, Objectcó một thuộc tính có thể thay đổi rất quan trọng, loại trừ lẫn nhau có liên quan!
Jan Hudec

@JanHudec: Tôi muốn nói rằng khóa màn hình trong Java và .NET được sử dụng Objectlàm mã thông báo nhận dạng. Trong phạm vi mà chúng được xem là đóng gói trạng thái có thể thay đổi trong một đối tượng, không có thứ gọi là vật thể bất biến. Thật trớ trêu khi Java đôi khi được xem như là một "ngôn ngữ giảng dạy", vì mục tiêu thiết kế quan trọng hơn là đơn giản hóa thời gian chạy bằng cách sử dụng một kiểu tham chiếu duy nhất; từ góc độ ngữ nghĩa, sẽ tốt hơn nếu phân biệt các loại có bản sắc với các loại không có. Lợi ích chính của các loại bất biến là ...
supercat

... rằng các trường hợp bất biến đóng gói cùng một trạng thái có thể được sử dụng thay thế cho nhau, nhưng không có cách nào một loại có thể đảm bảo điều đó. Nếu mã sử dụng new String("Hello");làm khóa trong một IdentityHashMapchuỗi, chuỗi sẽ trông giống như bất kỳ chuỗi nào khác đóng gói các ký tự đó vào bất kỳ mã nào không biết về bản đồ đó, nhưng nó sẽ không thể thay thế được vì đối tượng bên dưới của nó sẽ có mã thông báo nhận dạng khác với mọi đối tượng khác trong toàn bộ vũ trụ.
supercat

Việc khóa được chứa hay lưu trữ trong cấu trúc dữ liệu bên ngoài không quan trọng, về mặt ngữ nghĩa, nó hoạt động như một thuộc tính có thể thay đổi cho phép phân biệt danh tính của đối tượng. Và tôi gần như chắc chắn rằng tôi đã thấy mô tả cấp thấp của Đối tượng Java, nơi nó rõ ràng bao gồm khóa. Một trong những lý do cho sự kém hiệu quả của bộ nhớ Java.
Jan Hudec

@JanHudec: Về mặt ngữ nghĩa, không có đối tượng nào có thể bất biến hơn Object. Bất kỳ định nghĩa nào về tính bất biến cấp độ lớp sẽ được thỏa mãn bằng ví dụ Integersẽ được thỏa mãn như nhau Object. Hơn nữa, nói chung khi một đối tượng được cho là gói gọn trạng thái có thể thay đổi, có thể sao chép một cách có ý nghĩa trạng thái đó từ thể hiện này sang thể hiện khác. Tôi không nghĩ có bất kỳ cách nào để sao chép trạng thái khóa của đối tượng này sang đối tượng khác.
supercat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.