Tại sao một phương thức tĩnh được coi là một phương thức?


135

Tôi đang viết một lời giải thích cho một số mã cho một khóa học, và đã vô tình sử dụng các từ methodfunctionhoán đổi cho nhau. Tôi quyết định quay trở lại và sửa chữa từ ngữ, nhưng chạy vào một lỗ hổng trong sự hiểu biết của tôi.

Theo những gì tôi hiểu, chương trình con là functionnếu nó không hoạt động trên một thể hiện của một lớp (hiệu ứng của nó bị hạn chế đối với đầu vào / đầu ra rõ ràng của nó) và là methodnếu nó hoạt động trên một thể hiện của một lớp (nó có thể mang tác dụng phụ trên trường hợp làm cho nó không tinh khiết).

Có một cuộc thảo luận tốt ở đây về chủ đề này. Lưu ý rằng theo định nghĩa của câu trả lời được chấp nhận, một tĩnh methodthực sự phải là một hàm vì một thể hiện không bao giờ được truyền hoàn toàn và nó không có quyền truy cập vào bất kỳ thành viên nào.

Mặc dù vậy, đây không phải methodslà chức năng?

Theo định nghĩa của họ, họ không hành động theo các trường hợp cụ thể của một lớp; họ chỉ "gắn" với lớp vì mối quan hệ. Mặc dù vậy , tôi đã thấy một vài trang web ưa nhìn coi các chương trình con tĩnh là "phương thức" ( Oracle , Fredosaurus , Lập trình đơn giản ), vì vậy tất cả chúng đều nhìn vào thuật ngữ hoặc tôi thiếu một cái gì đó (tôi đoán là cái sau) .

Tôi muốn chắc chắn rằng tôi đang sử dụng từ ngữ chính xác.
Bất cứ ai có thể làm rõ điều này?


2
Tôi luôn nghĩ rằng đó là chức năng trong php và phương thức trong Java. Về cơ bản điều tương tự với các tên khác nhau
JK

19
Có một sự khác biệt giữa khoa học máy tính lý thuyết và cách ngôn ngữ áp dụng nó. JLS không phân biệt và gọi nó là một phương thức.
Jeroen Vannevel


2
Nó có thể là quan tâm đến cái nhìn tại các định nghĩa về "chức năng" và "phương pháp" bằng Python, nơi có một sự khác biệt: về cơ bản, một chức năng là một đoạn mã với một bảng biểu tượng và một quy ước gọi, trong khi một phương pháp là gì bạn nhận được khi bạn đặt một hàm vào một lớp. Sự khác biệt là khá tinh tế, ngay cả với những người biết Python.
David Z

2
Khi tôi đang học lý thuyết, tôi đã học hàm trả về một giá trị và thủ tục thì không. Sau đó, tôi học java gọi các hàm và phương thức thủ tục. Bây giờ tôi đang thử chương trình chức năng và một chức năng là idempotent. Các điều khoản thay đổi ý nghĩa trên bối cảnh.
emory

Câu trả lời:


123

Trích dẫn này từ 8.4.3.2 có thể giúp:

Một phương thức được khai báo staticđược gọi là phương thức lớp .

Một phương thức không được khai báo staticđược gọi là một phương thức thể hiện [...].

  • Các phương thức lớp: liên kết với một lớp.
  • Phương thức sơ thẩm: liên kết với một thể hiện.

Java chỉ muốn bạn "nghĩ theo hướng đối tượng". Ngoài ra, các phương thức tĩnh có quyền truy cập vào một phạm vi xung quanh có thể bao gồm trạng thái. Theo một cách nào đó, lớp giống như một đối tượng.


Điều đó đang được nói, trong khi "hàm" đúng về mặt kỹ thuật là một đơn vị thực thi trong Java, thì danh pháp ưa thích trong toàn bộ hầu hết Java là "phương thức", vì tất cả các hàm Java là một phần của một lớp hoặc giao diện (ngoại trừ lambdas và có thể một số điều khác tôi không biết).
Shotgun Ninja

1
Lambdas thực sự là các lớp bên trong vô danh với @FunctionalInterfacechú thích và với 1 phương thức dưới mui xe. Một lambda chỉ là đường cú pháp và về vấn đề đó không có gì mới.
Adam Arold

1
@AdamArold Lambdas khá hâm mộ hơn một lớp bên trong vô danh. Ví dụ, lambdas không bắt có thể chia sẻ một thể hiện qua nhiều đánh giá của một biểu thức cụ thể. (Nhưng bạn nói đúng, cuối cùng họ được biên dịch thành các phương thức tĩnh và cá thể.)
Radiodef

@Radiodef Có lẽ một cách tốt hơn để diễn đạt nó là "Tất cả các biểu thức lambda có thể được thay thế bằng các biểu thức không phải lambda tương đương, mà không thực hiện bất kỳ thay đổi nào đối với các tệp khác với biểu thức lambda" hoặc đại loại như thế.
dùng253751

4
Tôi xấu hổ. Tôi đến từ Scala và vẫn cố gắng bỏ lỡ thực tế rằng chính lớp đó giống như đối tượng. Cảm ơn bạn.
Carcigenicate

80

Câu trả lời đơn giản là khi Java quyết định gọi mọi thứ là "phương thức", họ không quan tâm đến sự khác biệt giữa chức năng và phương pháp trong khoa học máy tính lý thuyết.


3
Đúng rồi. Cho đến và bao gồm cả Java 7, bạn thậm chí sẽ không tìm thấy từ "hàm" trong Đặc tả ngôn ngữ
Erwin Bolwidt

4
Nhiều như tôi thích sự đơn giản của câu trả lời này, tôi nghĩ rằng câu trả lời của Radiodef có nhiều hướng đi hơn vì nó đề cập đến điểm chính mà chính lớp đó đóng vai trò là một đối tượng. Cảm ơn bạn mặc dù.
Carcigenicate

2
Thật thú vị, điều này song song với các quyết định của các ngôn ngữ trước đó không phân biệt giữa các chức năng và chương trình con.
Random832

4
Tôi ngạc nhiên khi thấy câu trả lời này nhận được rất nhiều sự ủng hộ. Đầu tiên, câu trả lời này giả vờ rằng các phương thức lớp không tồn tại. Thứ hai, đây hầu như không phải là một khái niệm được giới thiệu trong Java. Các phương thức lớp đã tồn tại trong Smalltalk, chẳng hạn, đã tồn tại hàng thập kỷ trước khi Java trở thành một thứ.
Malcolm

1
@Malcolm Tôi phải đồng ý với bạn. Sau khi xem xét các câu trả lời khác, điều này có vẻ sai. Đó không phải là sự thờ ơ về phía người tạo Java, trừ khi họ thực sự không quan tâm nhưng cuối cùng đã đặt tên chính xác cho nó.
Carcigenicate

26

Các phương thức tĩnh không chính xác là các hàm, sự khác biệt là tinh tế, nhưng quan trọng.

Một phương pháp tĩnh nhờ sủ dụng các thông số đầu vào chỉ cho cơ bản một hàm.

Nhưng các phương thức tĩnh có thể truy cập các biến tĩnh và các hàm tĩnh khác (cũng sử dụng các biến tĩnh) để các phương thức tĩnh có thể có trạng thái khác về cơ bản với một hàm theo định nghĩa không trạng thái . (ĐỊA CHỈ: Mặc dù các lập trình viên thường không quá khắt khe với việc sử dụng "hàm" như định nghĩa, một chức năng nghiêm ngặt trong khoa học máy tính chỉ có thể truy cập các tham số đầu vào). Vì vậy, việc xác định trường hợp truy cập các trường tĩnh này không hợp lệ để nói rằng các phương thức tĩnh luôn là các hàm.

Một điểm khác biệt nữa chứng minh việc sử dụng "phương thức tĩnh" là bạn có thể định nghĩa trong C dẫn xuất các hàm toàn cục và các biến toàn cục có thể được truy cập ở mọi nơi. Nếu bạn không thể truy cập lớp có chứa các phương thức tĩnh, thì các phương thức cũng không thể truy cập được. Vì vậy, "phương thức tĩnh" bị giới hạn trong phạm vi của chúng bởi thiết kế trái ngược với các chức năng toàn cầu.


2
Tôi thích câu trả lời này, nhưng muốn hiểu rõ hơn về một số điều. Đây không phải là một chức năng "thuần túy" so với "hiệu ứng phụ", chứ không phải là chức năng so với phương pháp? Hoặc là một phương pháp là như vậy vì tác dụng phụ? Tôi chỉ đang động não ở đây.
Nadir Sampaoli

2
Câu trả lời này là đúng. Tuy nhiên, người ta có thể lập luận rằng các hàm trong nhiều ngôn ngữ (hầu hết?) Có thể truy cập các biến toàn cục, vì vậy chúng thường không hoàn toàn không trạng thái (cùng một đầu vào, cùng một đầu ra). Và trong trường hợp các phương thức tĩnh Java, để truy cập các biến lớp có thể được coi là tương đương với truy cập các biến "toàn cầu" (nghĩa là không cục bộ đối với hàm / phương thức) - với thể hiện của lớp là một không gian tên.
leonbloy

1
@leonbloy Các ngôn ngữ lập trình chức năng thuần túy như Haskell hoàn toàn không trạng thái; không có gì có thể được gọi là một biến toàn cầu.
Thorsten S.

17

Trong Java, một lớp do người dùng định nghĩa thực sự là một thể hiện của một lớp con của java.lang.Class.

Theo nghĩa này, các phương thức tĩnh được gắn vào một thể hiện của một lớp khái niệm: chúng được gắn vào một thể hiện của một lớp con của java.lang.Class.

Với ý nghĩ này, thuật ngữ "phương thức lớp" (tên thay thế cho các phương thức tĩnh của Java) bắt đầu có ý nghĩa. Và thuật ngữ "phương thức lớp" có thể được tìm thấy ở nhiều nơi: Mục tiêu C, Smalltalk và JLS - để chỉ một vài tên.


Có thể có hai trường hợp của lớp con này?
Random832

Tất nhiên, bạn có thể tải một lớp trong các trình nạp lớp khác nhau (lý do nhận ClassCastExceptions với thông báo "không thể truyền CustomClass thành CustomClass").
dunni

2
@ Random832 - loại. Bạn có thể có hai (hoặc nhiều) phiên bản của cùng một lớp con trong cùng một JVM, miễn là mỗi cá thể có trình nạp lớp riêng biệt. Bạn không thể khởi tạo cùng một lớp con nhiều hơn một lần cho mỗi trình nạp lớp. Nó có một chút khó hiểu và tương tự như các khái niệm OO cổ điển bắt đầu bị kéo dài một chút mỏng tại thời điểm này.
Mike Clark

@MikeClark nếu tôi làm điều đó, họ có thực sự giống nhau không? Giống như, lớp con Class sẽ là cùng một lớp ngay cả khi chính lớp đó là một thể hiện khác của nó? Trình tải lớp khá khó hiểu với tôi. Tôi có thể gọi (không có sự phản chiếu) một phương thức tĩnh của một cá thể của trình nạp lớp của một lớp từ một cá thể của lớp khác của cùng một lớp không, bằng cách có một tham chiếu đến nó được truyền vào? Nếu họ có các phương pháp khác nhau thì sao?
Random832

1
@ Random832 "Sắp xếp?" Từ quan điểm lý thuyết OO thuần túy, có hai trường hợp nào của một lớp thực sự giống hệt nhau không? Ít nhất hai trường hợp giống hệt nhau của cùng một lớp sẽ có địa chỉ khác nhau. Nếu không, làm thế nào chúng ta có thể có hai điều? Điều duy nhất đó là chính xác giống như một cái gì đó, là điều chính nó.
Mike Clark

11

Trong chức năng khoa học máy tính rõ ràng ánh xạ đến một phương pháp tĩnh. Nhưng "phương thức" của một lớp là hơi chung chung, như "thành viên" (thành viên trường, thành viên phương thức). Có những từ như

Thành viên dữ liệu và thành viên phương thức có hai không gian tên riêng biệt: .x và .x () có thể cùng tồn tại.

Vì vậy, lý do là, như triết gia Ludwig Wittgenstein đã nói, Ngôn ngữ là một công cụ với các bối cảnh khác nhau. "Phương pháp" là một biệt danh tốt đẹp trong trích dẫn ở trên để phân loại "thành viên".


9

Suy nghĩ của bạn là đúng và nó có ý nghĩa. Nó chỉ không được thiết lập thuật ngữ trong cộng đồng Java. Hãy để tôi giải thích một số nội bộ có thể giúp hiểu lý do tại sao các thuật ngữ tồn tại.

Java là một ngôn ngữ hướng đối tượng dựa trên lớp. Một phương thức luôn là thành viên của một lớp hoặc thể hiện (Đây là một câu lệnh chung hợp lệ cho các ngôn ngữ lập trình khác). Chúng tôi nghĩ về lớp và thể hiện là cả hai đối tượng.

Phương pháp sơ thẩm (động)

Bạn không thể gọi phương thức này trực tiếp từ một lớp, bạn phải tạo một thể hiện. Mỗi trường hợp tham chiếu phương thức đó. Bạn có thể ghi đè một định nghĩa phương thức với chữ ký phương thức chính xác (khi phân lớp), tức là các tham chiếu trỏ đến một phương thức khác (có cùng chữ ký, nhưng có thể có thân phương thức khác). Phương pháp là năng động.

Phương thức lớp (tĩnh)

Bạn chỉ có thể gọi phương thức này trực tiếp từ lớp, tức là bạn không cần tạo một thể hiện của lớp đó. Chỉ có một định nghĩa toàn cầu về phương pháp đó trong toàn bộ chương trình. Bạn không thể ghi đè chính xác chữ ký phương thức khi phương thức được khai báo tĩnh, vì chỉ có một định nghĩa hợp lệ cho toàn bộ chương trình. Lưu ý rằng phương thức là thành viên của chính đối tượng lớp, các thể hiện có tất cả cùng một tham chiếu (và sửa lỗi) cho phương thức đó.


7

Đây là một cách khác về thuật ngữ, sử dụng Scala như một cách ghi nhớ:
Trong Scala, bạn có objects, là các trường hợp đơn lẻ của một lớp được định nghĩa ngầm1 .

Theo định nghĩa của bạn, chúng ta có thể gọi các chương trình con này thuộc về các object phương thức , vì chúng hoạt động trên một thể hiện duy nhất của lớp.
Ngoài ra, đối tượng cũng sẽ định nghĩa lớp A và tạo tất cả các phương thức trong đối tượng A làm phương thức tĩnh trên lớp A (để giao tiếp với Java) [2] .

Do đó, chúng ta có thể nói rằng các phương thức tĩnh của lớp Java A truy cập cùng các thành viên như cá thể Scala singleton, theo định nghĩa của bạn sau đó xứng đáng được gọi là phương thức (tĩnh) của lớp A.


So sánh tuyệt vời. Tôi biết Scala, vì vậy objecttài liệu tham khảo của bạn rất có ý nghĩa. Cảm ơn bạn.
Carcigenicate

2

Tất nhiên, sự khác biệt chính là - phương thức có thể sử dụng các trường tĩnh, không chỉ các tham số của phương thức. Nhưng có thêm một - đa hình! Kết quả đánh giá Lớp A.doTheSameStaticMethod () và ClassB.doTheSameStaticMehod () sẽ phụ thuộc vào lớp. Trong trường hợp này chức năng là bất lực.


1

Mỗi lớp có một đối tượng để thể hiện nó là một thể hiện của một lớp con của Classlớp. Các phương thức tĩnh là các phương thức thực sự trên các đối tượng này là các thể hiện của một lớp con của Class. Chúng có quyền truy cập vào trạng thái dưới dạng các trường tĩnh, vì vậy chúng không bị hạn chế chỉ là các hàm (không trạng thái). Chúng là phương pháp.

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.