【问题标题】:Are there any side effect of using to many static function?使用许多静态函数有副作用吗?
【发布时间】:2011-09-14 07:53:06
【问题描述】:

目前我对 play 框架很感兴趣,因为这个框架承诺更快的开发。

当我看到代码时,有很多静态代码。甚至声明为静态函数的控制器。所以所有在静态函数内部调用的代码都必须是静态的吧?

我的问题是,这种方法是否正确?使用很多静态函数有什么副作用吗?

【问题讨论】:

  • 静态方法可以调用作为参数传递或在静态字段中传递的实例的非静态方法,或它们创建的对象。没有实例就不能调用同一个类的非静态方法。

标签: java playframework


【解决方案1】:

之前有人以类似的方式提出过这个问题。简单的答案是 Play 在合理的地方使用了静态。

HTTP 模型不是 OO 模型。 HTTP 请求本身是无状态的,因此静态方法允许作为来自客户端代码的功能性请求访问控制器。

另一方面,Model 类是纯 OO,因此不是静态重的。 一些实用方法,例如 findAll 或 findById 是静态的,但这些也不是有状态的,并且是类上的实用方法。无论如何,我希望在标准的 OO 模型中做到这一点。

因此,我认为按照 Play 预期的方式做事没有任何风险。它可能看起来很奇怪,因为它挑战了规范,但这样做是有充分理由的。

【讨论】:

  • 这是正确的答案,因为它专门适用于 Play Framework。
  • 从 Play Framework 食谱第 15 页,它表明创建者很好地解决了这个问题(play.classloading.enhancers.ControllerEnhancer)
  • 他确实做到了。 Guillaume 是个很聪明的人,Play 团队把 Play 的结构设计得很好。
【解决方案2】:

关于面向对象语言中的静态方法的几件事:如果您选择使用所有静态方法,让我试着解释一下问题。

在面向对象的语言中,使用所有静态函数可能不是惯用的。 您不能覆盖子类中的静态函数。因此,您将失去通过覆盖来执行运行时多态性的能力。

您定义的所有变量都会自动成为类变量(因为您的所有方法都是静态的),因此本质上您没有与实例关联的任何状态。

静态方法很难模拟。您可能需要像 PowerMock 这样的框架来为您进行模拟。所以测试变得困难。

设计变得有点复杂,因为您将无法创建不可变的类,因为您实际上只有类而没有实例。所以设计线程安全的类变得很困难。

【讨论】:

  • 为了测试,Play Framework 使用 JUNIT4 和 Selenium。我认为足以创建单元测试和回归测试
  • “所以设计线程安全的类变得困难”根据您的评论,在企业应用程序中使用播放框架不是很好吗?
  • 让我澄清一下。为不变性设计一个类是一种无需引入同步即可设计线程安全类的方法。当然,当您需要更改对象的状态时,您必须创建该类的新实例。例如,查看 String 类。但是如果你的方法都是静态的并且你只有类变量,那么一个不可变的类是不可能的,因为没有实例。我并不是说只有静态方法的类不能是线程安全的。
  • @indrap。良好的 OO 设计可确保解耦类。这样做的一个好方法是注入您的依赖项。单独测试类是编写单元测试的好方法。为了单独测试类,您需要模拟依赖项。由于静态方法不能被覆盖,您需要一个像 powermock 这样的字节码操作库来为您进行模拟。这就是我所说的测试变得困难时的意思。
  • “现在一些 Java 开发人员可能会因为“控制器中的静态方法不是线程安全的!”而痛苦地尖叫。但是,为了使某些调用线程安全,控制器对字节码进行了增强,所以开发人员不必担心此类问题。如果您有兴趣了解更多信息,您可能需要检查类 play.classloading.enhancers.ControllerEnhancer" 这是来自 Play Framework Cookbook 第 15 页的评论的一部分,显示创建者有已妥善解决胎面安全问题。
【解决方案3】:

详细说明我的评论。

静态方法可以调用非静态方法,前提是你有一个实例。

class A {
   public void nonStaticMethod() { }

   public static void staticMethod(String text) {
      // calls non-static method on text
      text.length();
      // calls non-static method on new Object
      new Object().hashCode();
      // calls non static method on a instance of A
      new A().nonStaticMethod();
   }
}

【讨论】:

  • 我明白你的意思,谢谢。我可以使用 google guice 创建对象实例,然后在控制器中使用非静态函数
【解决方案4】:

是的,使用过多的静态函数或变量会产生副作用。 您应该避免不必要的静态声明。

因为一旦类被加载到 JRE 中,静态成员总是会创建一个内存空间。即使不创建类的对象也会占用内存。

【讨论】:

  • 由于控制器使用静态类,因此在控制器内部调用的所有函数或类都必须是静态的。我认为在这种情况下,静态使用是非常必要的。
  • 这个答案不正确。静态方法使用的空间不比实例方法多或少。是否创建类的实例也没有区别。
  • OP 询问的是静态函数,而不是静态字段。静态字段将在加载类后立即分配空间,而实例字段在创建实例之前不会分配(但是,为静态字段分配的内存仅分配一次,但实例字段为 every 实例)。正如@stephenc 所说,方法没有区别。
  • 静态方法和非静态(实例)方法在幕后的唯一区别是一个额外的隐藏参数(this)被传递给实例方法,并且可以使用间接调用实例方法调度(如果是虚拟的)。没有占用额外的代码空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 2014-08-02
  • 2010-11-27
  • 2013-11-03
  • 2019-03-03
  • 1970-01-01
相关资源
最近更新 更多