【问题标题】:Why does having static members make a language less object-orientated?为什么拥有静态成员会使语言不那么面向对象?
【发布时间】:2014-04-06 04:34:10
【问题描述】:

我现在正在学习 Scala,我在 Odersky 的 Programming Scala 2nd edition 中看到了这个声明:

Scala 比 Java 更面向对象的一种方式是 Scala 中的类不能有静态成员。

我在 Java 或 Scala 方面的经验不足,无法理解这种比较。为什么拥有静态成员会使语言不那么面向对象?

【问题讨论】:

  • 我在这里回复你所有的答案。所以基本上你们都说的是,为了成为一种纯粹的面向对象语言,语言必须始终对对象进行操作(即必须实例化类)。如果允许我在不实例化类的情况下调用类的各个方面,这是否违反了纯 OO 理论?
  • 不要回复这样的答案。这不会通知任何人,因此他们不会知道要检查。
  • @I.K.我想我们说的是我们认为奥德斯基的想法,尽管我们中的一些人可能不同意。归根结底,这个主题几乎是基于意见的。

标签: java scala


【解决方案1】:

我不确定我是否完全认同这个论点,但这是一种可能的推理。

对于一个面向对象的纯粹主义者来说,一切都应该是一个对象,所有的状态都应该被对象封装。类的任何static 成员都是定义状态,它存在于对象之外,因为您可以在不实例化对象的情况下使用和操作它。因此,缺少静态类成员使得语言更加纯粹。

【讨论】:

  • 我同意这可能是争论背后的原因。然而,在 Java 中,类是对象,所以在我看来这个论点是虚假的。
  • @WarrenDew,这纯粹是我们的猜测。 :P
  • @Warren 注意,Java 类有一个对应的 Class 对象,但在调用静态方法时并没有涉及。
  • @SotiriosDelimanolis 在类加载器将类对象加载到内存之前,您不能调用静态方法。
  • @Warren 当然,但这不相关。不会在 Class 对象上调用静态方法,也不会影响其任何状态。在任何意义上的 OOP 术语中,两者都是完全无关的。
【解决方案2】:

奥德斯基的说法是有效且重要的,但有些人不明白他的意思。

假设在 Java 中有一个类 Foo,其方法为 f:

class Foo {
  int f() { /* does something great */ }
}

您可以编写一个接受 Foo 并在其上调用 f 的方法:

void g(Foo foo) { foo.f(); }

也许有一个类 SubFoo 扩展了 Foo; g 也适用于此。可以有一整套类,通过继承或接口相关,它们共享可以与 g 一起使用的事实。

现在让我们将 f 方法设为 静态

class Foo {
  static int f() { /* does something great */ }
}

我们可以将这个新的 Foo 与 g 一起使用吗,也许像这样?

g(Foo);  // No, this is nonsense.

该死。好的,让我们更改 g 的签名,以便我们可以将 Foo 传递给它并让它调用 f。

糟糕——我们不能。我们不能传递对 Foo 的引用,因为 Foo 不是某个类的实例。在这里评论的一些人对存在与 Foo 对应的 Class 对象这一事实感到困惑,但正如 Sotirios 试图解释的那样,Class 对象没有 f 方法,而 Foo 不是该类的实例。 Foo 不是任何事物的实例;它根本不是一个对象。 Foo 的 Class 对象是 Class Class 的实例,其中包含有关 Foo 的信息(将其视为 Foo 的内部 Wikipedia 页面),并且与讨论完全无关。 “老虎”的维基百科页面不是老虎。

在 Java 中,像 3 和 'x' 这样的“原语”不是对象。它们 Scala 中的对象。为了提高性能,您的程序将在执行期间尽可能使用 JVM 原语 3 和“x”,但在您编写代码的级别上,它们实际上是对象。它们在 Java 中不是 对象这一事实对于任何试图编写处理所有数据类型的代码的人来说都是相当不幸的后果——你必须有特殊的逻辑和额外的方法来覆盖原语。如果你曾经见过或写过这种代码,你就会知道它很糟糕。奥德斯基的说法不是“纯粹主义”;远非如此。

在 Scala 中,没有任何运行时数据不是对象,也没有可以调用方法的东西不是对象。在 Java 中,这些陈述都不是真的; Java 是一种部分面向对象的语言。在 Java 中有些东西不是对象,有些方法不在对象上。

Scala 的新手经常认为object Foo 是 Java 静态的一些奇怪的替代品,但这是您需要尽快克服的问题。而是将 Java 的静态方法视为非 OO 疣,而将 Scala 的 object Foo { ... } 视为类似以下内容:

class SomeHiddenClass { ... }
val Foo = new SomeHiddenClass  // the only instance of it

这里的Foo是一个value,而不是一个type,它确实是一个对象。它可以传递给一个方法。它可以扩展一些其他类。例如:

abstract class AbFoo { def f:Int }
object Foo extends AbFoo { def f = 2 }

现在,终于可以说

g(Foo)

确实,类的“伴生对象”是放置类的非实例方法和数据的好地方。但是那个伴生对象是一个对象,所以通常的规则和能力适用。

在 Java 中,您将此类方法放在非对象上——限制了它们的使用方式——这一事实是一种责任,而不是一种特性。这肯定是不是 OO。

【讨论】:

  • 我理解为什么奥德斯基教授会说他现在所说的。很棒的帖子。
  • 这当然是最好的答案,尤其是最后一部分,由 J Mittag 先生中午的回答补充。这是对 Warren Dew 反驳的回应。希望绿色检查缺陷。
  • 同意,因为我想知道为什么 Odersky 教授声称 Scala 比 Java 更像是一种 OO 语言。这篇文章对此进行了解释,而其他文章只是一般性地解释了为什么静态方法使语言不那么 OO。
【解决方案3】:

好吧,对于静态成员(如方法),您无需创建任何对象,但您仍可以调用此类静态方法。您只需要静态类名即可为这些方法设置命名空间,例如:

long timeNow = System.currentTimeMillis(); // no object creation

这更像是一种程序语言的感觉。

【讨论】:

    【解决方案4】:

    静态成员属于类而不属于对象,而oop的主要概念在于dirrefer Class的各个对象之间的关系。

    【讨论】:

      【解决方案5】:

      Java 中的static 方法是对类本身进行操作的方法,不需要首先创建对象。例如这一行:

      int c = Integer.parseInt("5");
      

      Integer.parseInt() 是静态的,因为在使用它之前我不必去Integer i = new Integer();;这不是对我创建的任何特定对象进行操作,因为它总是相同的,并且更像是典型的过程函数调用而不是面向对象的方法。如果我必须为每个调用创建一个对象,并且我们以这种方式封装所有内容,而不是允许 static 将方法用作虚假过程函数,那么它会更加面向对象。

      【讨论】:

        【解决方案6】:

        确切面向对象的含义有几个相互竞争的定义。但是,他们都同意一件事:动态调度是 OO 定义的基本部分。

        静态方法是静态的(废话),不是动态的,因此它们根据定义不是面向对象的。

        从逻辑上讲,具有非面向对象特性的语言在某种意义上比没有上述特性的语言“更少 OO”。

        【讨论】:

        • 是的,其他人都这么说。但我需要知道的是,为什么 Scala 比 java 更像是一种 OO 语言。对我来说,以我目前对 Scala 的了解,Odersky 教授所做的只是从类定义中取出静态成员并将它们放入伴生对象中。类和伴生对象仍然可以引用彼此的私有成员。这只是做同一件事的不同方式。所以在我看来,scala 并不比 Java 更面向对象,反之亦然。也许我错了?
        猜你喜欢
        • 2012-01-21
        • 2010-09-06
        • 2023-03-06
        • 2011-06-18
        • 2016-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多