为什么将静态方法视为方法?


135

我正在为某门课程的一些代码编写解释,并且偶然使用了这些单词method并且function可以互换使用。我决定回过头来修正措辞,但在我的理解上遇到了一个漏洞。

据我了解,子例程是一个function如果它不作用于一个类的实例(其作用仅限于其显式输入/输出),并且是一个method如果它作用于一个类的实例(它可能带有消除导致实例不纯的副作用)。

关于这个话题,这里很好的讨论。请注意,根据接受的答案的定义,静态method实际上应该是一个函数,因为永远不会隐式传递实例,并且它无法访问任何实例的成员。

有了这个主意,静态不应该methods是函数吗?

根据它们的定义,它们不作用于类的特定实例;他们只是因为关系而“束缚”在班上。我见过一些外观不错的站点,尽管它们将静态子例程称为“方法”(OracleFredosaurusProgrammingSimplified),所以它们要么都忽略了术语,要么我就漏掉了一些东西(我猜是后者) 。

我想确保我使用的措词正确。
有人可以清除吗?


2
我一直认为这是PHP中的功能,而Java中是方法。基本上是相同的东西
JK

19
理论计算机科学与语言如何应用之间存在差异。JLS没有区别,将其称为方法。
Jeroen Vannevel 2015年


2
这可能会感兴趣的看“功能”和Python的,那里有“法”的定义一个区别:基本上,一个功能是用符号表的代码和调用约定块,而方法是什么当您将函数放入类时,您会得到。但是,即使对于了解Python的人来说,差异也非常微妙。
David Z

2
当我学习理论时,我学习到函数返回一个值,而过程则不返回。然后,我学习了Java调用函数和过程的方法。现在我正在尝试函数编程,并且函数是幂等的。术语改变了上下文的含义。
2015年

Answers:


123

8.4.3.2中的引号可能有帮助:

声明的static方法称为类方法

没有声明的static方法称为实例方法 [...]。

  • 类方法:与一个类相关联。
  • 实例方法:与实例关联。

Java只希望您“思考面向对象”。同样,静态方法可以访问可能包含状态的周围环境。在某种程度上,该类就像一个对象本身。


话虽这么说,虽然“功能”在Java中作为执行单元在技术上是正确的,但在整个Java中,首选的命名法是“方法”,因为所有Java函数都是类或接口的一部分(lambda除外,也许其他一些我不知道的事情。
Shot弹枪忍者

1
Lambda实际上是带有@FunctionalInterface注释和后台方法的匿名内部类。Lambda只是语法糖,在这方面没有新内容。
亚当·阿罗德

1
@AdamArold Lambdas比匿名内部类要漂亮得多。例如,非捕获lambda可以跨特定表达式的多个求值共享一个实例。(但您是对的,它们最终最终被编译为静态方法和实例方法。)
Radiodef 2015年

@Radiodef也许是一种更好的措辞,它是“可以将所有的lambda表达式替换为等效的非lambda表达式,而不对包含lambda表达式的文件以外的文件进行任何更改”或类似的方式。
user253751

4
我很尴尬。我来自Scala,仍然设法忽略了类本身是对象的事实。谢谢。
Carcigenicate,2015年

80

简单的答案是,当Java决定将一切都称为“方法”时,他们并不关心理论计算机科学中函数与方法之间的区别。


3
那就对了。在Java 7之前(包括Java 7),您甚至在语言规范中都
Erwin Bolwidt,2015年

4
尽管我喜欢这个答案的简单性,但我认为Radiodef的答案更加合理,因为它提到了类本身充当对象的关键点。不过谢谢你
Carcigenicate,2015年

2
有趣的是,这与早期语言的决定(不区分函数和子例程)平行。
Random832

4
令我惊讶的是,这个答案获得了如此多的好评。首先,这个答案假装类方法不存在。其次,这几乎不是Java引入的概念。例如,Smalltalk中已经存在类方法,这种方法在Java成为事物之前已经存在了数十年。
马尔科姆

1
@马尔科姆我必须同意你的观点。考虑其他答案后,这似乎是错误的。对Java创建者而言,这并不是冷漠,除非他们真的不在乎,但最终无论如何都正确地命名了它。
Carcigenicate,2015年

26

静态方法并不完全是函数,区别是微妙的,但很重要。

只使用给定的输入参数的静态方法本质上的功能。

但是静态方法可以访问静态变量和其他静态函数(也使用静态变量),因此静态方法的状态可能与定义为无状态的函数在根本上不同。(附录:尽管程序员通常不那么严格地使用“函数”作为定义,但是计算机科学中的严格函数只能访问输入参数)。因此,定义这种访问静态字段的情况并不能说静态方法始终是函数。

证明使用“静态方法”的另一个区别是,您可以在C中定义派生的全局函数和全局变量,它们可以在任何地方访问。如果您无法访问包含静态方法的类,则这些方法也将无法访问。因此,与全局功能相比,“静态方法”的设计范围受到了限制。


2
我有点喜欢这个答案,但想更好地理解一些东西。这不是更“纯” vs“副作用”功能,而不是功能vs方法吗?还是因为副作用而采用这种方法?我只是在这里集思广益。
2015年

2
这个答案是正确的。但是,人们可能会争辩说,许多(大多数)语言中的函数都可以访问全局变量,因此它们通常不是严格无状态的(相同的输入,相同的输出)。在Java静态方法的情况下,访问类变量可被视为等效于访问“全局”(即,不是函数/方法的局部变量)-类实例是一种命名空间。
leonbloy 2015年

1
@leonbloy 像Haskell 这样的纯函数式编程语言是完全无状态的。没有什么可以称为全局变量。
Thorsten S.

17

在Java中,用户定义的类实际上是java.lang.Class子类的实例。

从这个意义上说,静态方法附加到概念类的实例:它们被附加到java.lang.Class子类的实例。

考虑到这一点,术语“类方法”(Java静态方法的备用名称)开始变得有意义。术语“类方法”可以在很多地方找到:Objective C,Smalltalk和JLS,仅举几例。


是否可以有两个该子类的实例?
2015年

当然,您可以在不同的类加载器中加载类(获得带有消息“无法将CustomClass转换为CustomClass”的ClassCastExceptions的原因)。
dunni 2015年

2
@ Random832-有点。您可以在同一JVM中具有两个(或更多)相同的Class子类的实例,只要每个实例具有自己的单独的类加载器即可。每个类加载器不能多次实例化同一Class子类。这有点令人困惑,并且与经典的OO概念的类比在此时开始变得越来越薄。
Mike Clark

@MikeClark如果我这样做,他们真的一样吗?就像,即使子类本身是该类的不同实例,该类子类也将是同一类吗?类加载器让我很困惑。我可以通过传递对它的引用而从一个类加载器的同一个类的实例中调用一个类加载器的静态实例(不带反射)吗?如果他们有不同的方法怎么办?
Random832

1
@ Random832“排序?” 从纯粹的面向对象理论的角度来看,一个类的任何两个实例是否真的完全相同?至少在其他情况下,相同类的两个相同实例将具有不同的地址。否则,我们怎么能拥有两个东西?唯一与事物完全相同的是事物本身。
Mike Clark

11

在计算机科学中,功能显然映射到静态方法。但是类的“方法”有点通用,例如“成员”(字段成员,方法成员)。有这样的措辞

数据成员和方法成员具有两个单独的名称空间:.x和.x()可以共存。

因此,原因是,正如哲学家路德维格·维特根斯坦(Ludwig Wittgenstein)所说,语言是具有不同上下文的工具。在上面的引用中,“方法”是一个很好的绰号,用于对“成员”进行分类。


9

您的想法是正确的,这是有道理的。它只是Java社区中尚未建立的术语。让我解释一些可以帮助理解术语存在的内在因素。

Java是一种基于类的面向对象语言。方法始终是类或实例的成员(这是一条对其他编程语言也有效的通用语句)。我们认为类和实例都是对象。

实例方法(动态)

您不能直接从类中调用此方法,而必须创建一个实例。每个实例都引用该方法。您可以使用完全相同的方法签名(在子类化时)覆盖方法定义,即,引用指向不同的方法(具有相同的签名,但可以具有不同的方法主体)。该方法是动态的。

类方法(静态)

您只能直接从类中调用此方法,即不需要创建该类的实例。在整个程序中,该方法只有一个全局定义。将方法声明为静态时,不能覆盖完全相同的方法签名,因为对于整个程序只有一个定义有效。注意,该方法是类对象本身的成员,实例具有对该方法的所有相同的唯一(和修复)引用。


7

这是使用Scala作为助记符的术语的另一种用法:
在Scala中,您有objects,它们是隐式定义的类的单例实例。1

根据您的定义,我们可以调用这些属于object 方法的子例程,因为它们在类的单个实例上进行操作。
另外,对象还将定义类A,并在类A上将对象A中的所有方法创建为静态方法(用于与Java接口) [2]

因此,可以说Java类A的静态方法访问与Scala单例实例相同的成员,根据您的定义,这些成员应被称为类A的(静态)方法


很棒的比较。我知道Scala,所以您的object参考很有道理。谢谢。
Carcigenicate,2015年

2

当然,主要区别在于-方法可以使用静态字段,而不仅仅是方法参数。但是还有另外一个-多态!评估类A.doTheSameStaticMethod()和ClassB.doTheSameStaticMehod()的结果将取决于类。在这种情况下,功能是无能为力的。


1

每个类都有一个对象来表示它,它是Class该类子类的一个实例。静态方法实际上是这些对象上的实例方法,这些对象是Class的子类的实例。它们可以以静态字段的形式访问状态,因此它们不仅限于仅(无状态)功能。他们是方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.