Java 为什么不';静态方法被认为是良好的OO实践吗?

Java 为什么不';静态方法被认为是良好的OO实践吗?,java,scala,oop,static-methods,language-concepts,Java,Scala,Oop,Static Methods,Language Concepts,我在看书。在第4章的开头,作者评论说Java支持静态方法,它们“不是那么纯粹的OO概念”。为什么会这样?静态方法不是那么纯粹的OO概念,因为它们可以在没有对象实际关联的情况下被调用。您可以使用类本身。您可以这样调用它们Classname.method(…)OO的概念是谈论从对象控制/访问数据,但静态方法不需要使用对象调用,它们属于类而不是对象 --干杯不要把“不那么纯粹的OO概念”和“糟糕的实践”混为一谈。“纯OO”并不是您应该尝试实现的灵丹妙药。静态方法不将实例变量作为参数并不意味着它们没有用

我在看书。在第4章的开头,作者评论说Java支持静态方法,它们“不是那么纯粹的OO概念”。为什么会这样?

静态方法不是那么纯粹的OO概念,因为它们可以在没有对象实际关联的情况下被调用。您可以使用类本身。您可以这样调用它们
Classname.method(…)

OO的概念是谈论从对象控制/访问数据,但静态方法不需要使用对象调用,它们属于类而不是对象

--干杯

不要把“不那么纯粹的OO概念”和“糟糕的实践”混为一谈。“纯OO”并不是您应该尝试实现的灵丹妙药。静态方法不将实例变量作为参数并不意味着它们没有用处。有些东西就是不适合对象,它们不应该仅仅为了“纯洁”而被迫进入那个模子

有些人认为事物应该是“纯洁的”,因此任何“不纯洁”的东西都是不好的做法。实际上,糟糕的做法只是做一些令人困惑、难以维护、难以使用的事情。创建获取实例的静态方法是糟糕的做法,因为任何获取实例的方法都可能是实例方法。另一方面,像实用程序和工厂函数这样的东西通常不带实例,所以它们应该是静态的


如果你想知道为什么它们不是“纯OO”,那是因为它们不是实例方法。一个“纯”的OO语言将所有的东西都是一个对象,所有的函数都是实例方法。当然,这并不总是非常有用。例如,考虑<代码>数学。ATAN2方法。它需要两个数字,不需要任何状态。你能把它当作一种方法吗?在“纯”OO语言中,
Math
本身可能是一个对象(可能是一个单例),而
atan2
可能是一个实例方法,但由于函数实际上不使用
Math
对象中的任何状态,因此它也不是一个“纯OO”概念。

到目前为止,静态方法不是非常面向对象的一个原因是接口和抽象类只定义非静态方法。因此,静态方法不太适合继承

还请注意,静态方法无权访问“
super
”,这意味着静态方法不能在任何实际意义上被重写。实际上,它们根本不能被覆盖,只能被隐藏。试试这个:

public class Test {
    public static int returnValue() {
        return 0;
    }

    public static void main(String[] arg) {
        System.out.println(Test.returnValue());
        System.out.println(Test2.returnValue());
        Test x = new Test2();
        System.out.println(x.returnValue());
    }
}


public class Test2 extends Test {
    public static int returnValue() {
        return 1;
    }
}
当你运行这个时,你不会得到你所期望的
Test.returnValue()
给出了您所期望的结果
Test2.returnValue()
隐藏超类中同名的方法(它不会覆盖它),并给出您所期望的结果

人们可能天真地期望“非静态”调用静态方法来使用多态性。没有。变量声明为的任何类都是用于查找方法的类。这是一种糟糕的形式,因为有人可能期望代码执行与实际不同的操作


这并不意味着“不要使用静态方法!”而是意味着您应该为那些确实希望类对象拥有该方法的实例保留静态方法的使用,而不仅仅是作为生成单例的惰性方式。

面向对象涉及三件事:

  • 信息
  • 状态进程的本地保留、保护和隐藏,以及
  • 所有事物的极端后期绑定
在这三个方面中,最重要的是信息传递

静态方法至少违反消息传递和后期绑定

消息传递的思想意味着在OO中,计算是由相互发送消息的自包含对象网络执行的。发送消息是通信/计算的唯一方式

静态方法不能做到这一点。它们与任何对象都没有关联。根据通常的定义,它们实际上根本不是方法。它们实际上只是程序。Java静态方法
Foo.bar
和基本子例程
Foo\u bar
之间几乎没有区别

至于后期绑定:更现代的名称是动态调度。静态方法也违反了这一点,事实上,它甚至以它们的名字命名:静态方法

静态方法打破了面向对象的一些非常好的特性。例如,面向对象的系统自动实现了功能安全,对象充当功能。静态方法(或者任何静态方法,不管是静态方法还是静态方法)会破坏该属性


您还可以在每个对象自己的进程中并行执行每个对象,因为它们只通过消息传递进行通信,从而提供一些简单的并发性。(基本上就像演员一样,这不应该太令人惊讶,因为卡尔·休伊特基于Smalltalk-71创建了演员模型,艾伦·凯(Alan Kay)部分基于PLANNER创建了Smalltalk-71,而PLANNER又由卡尔·休伊特创建。演员和对象之间的密切关系绝非巧合,事实上,他们本质上是一对一同样,静态(包括静态方法,尤其是静态)破坏了这种良好的特性。

静态方法会导致紧密耦合,这违反了良好的面向对象设计。调用代码和静态方法中的代码之间的紧密耦合无法通过依赖项反转来避免,因为静态方法本身不支持面向对象的设计技术,如继承和多态性


此外,由于这些紧密耦合的依赖关系,静态方法很难测试,这通常会导致代码依赖的第三方基础设施,如数据库,这使得在不实际进入并更改代码的情况下更改行为非常困难。

静态方法被认为不好