【问题标题】:When to use static methods何时使用静态方法
【发布时间】:2011-02-09 22:03:57
【问题描述】:

我想知道什么时候使用静态方法?假设我有一个带有几个 getter 和 setter 的类,一个或两个方法,并且我希望这些方法只能在类的实例对象上调用。这是否意味着我应该使用静态方法?

例子:

Obj x = new Obj();
x.someMethod();

...或:

Obj.someMethod(); // Is this the static way?

我很困惑!

【问题讨论】:

标签: java static-methods


【解决方案1】:

我找到了一个很好的描述,什么时候使用静态方法:

没有硬性规定,写得很好的规则来决定何时使方法静态,但很少有基于经验的观察,这不仅有助于使方法静态,而且还教导何时使用静态Java中的方法。您应该考虑在 Java 中将方法设为静态:

  1. 如果一个方法没有修改对象的状态,或者没有使用任何实例变量。

  2. 您想调用方法而不创建该类的实例。

  3. 一个方法是静态的很好的候选者,如果它只对提供给它的参数起作用,例如。 public int factorial(int number){},此方法仅对作为参数提供的数字进行操作。

  4. 实用方法也是静态的很好的候选者,例如StringUtils.isEmpty(String text),这是一个检查字符串是否为空的实用方法。

  5. 如果方法的函数在类层次结构中保持静态,例如equals() 方法不适合做静态,因为每个类都可以重新定义相等性。

来源是here

【讨论】:

    【解决方案2】:

    一个经验法则:问问自己“调用此方法是否有意义,即使尚未构造任何对象?”如果是这样,它肯定应该是静态的。

    所以在 Car 类中你可能有一个方法:

    double convertMpgToKpl(double mpg)
    

    ...这将是静态的,因为人们可能想知道 35mpg 转换为什么,即使没有人构建过Car。但是这种方法(它设置了一个特定的Car的效率):

    void setMileage(double mpg)
    

    ...不能是静态的,因为在构造任何 Car 之前调用该方法是不可思议的。

    (顺便说一句,反过来并不总是正确的:您有时可能有一个涉及两个 Car 对象的方法,但仍然希望它是静态的。例如:

    Car theMoreEfficientOf(Car c1, Car c2)
    

    虽然这可以转换为非静态版本,但有些人会争辩说,由于没有“特权”选择哪个Car 更重要,你不应该强迫调用者选择一个@987654331 @ 作为您将调用该方法的对象。不过,这种情况只占所有静态方法的一小部分。

    【讨论】:

    • 这里有几个很好的例子。但是,我要补充一点,当您知道某些内容不会在实例之间发生变化时,“静态”通常很有价值。如果是这种情况,我真的会考虑“单一责任原则”,这意味着一个类应该有一个责任,因此只有一个改变的理由。我觉得应该考虑将“ConvertMpgToKpl(double mpg)”函数和类似方法移到他们自己的类中。汽车对象的目的是允许汽车的实例化,而不是提供它们之间的比较。这些应该是类外部的。
    • 我想我更喜欢Car#isMoreEfficientThan(Car)的方法。它的优点是,你在平局中返回哪辆车不是任意的。方法的标题很明显,返回的是平局。
    • 我也会小心创建一个使用某些外部资源(文件系统、数据库等)的静态方法,这种类型的静态方法会使测试消耗方法变得可怕。我个人尝试将静态保持在“实用性”领域。
    • 其实应该实现为Comparator
    • @B1KMusic 当然。我所说的“平局归还哪辆车”的意思是“真实映射到被调用的汽车,而虚假映射到经过的汽车”。没有歧义。
    【解决方案3】:

    当您不想创建对象来调用代码中的方法时,只需将该方法声明为静态。由于静态方法不需要调用实例,但这里的问题并不是所有静态方法都由 JVM 自动调用。此特权仅由 java 中的 main() "public static void main[String...args]" 方法享有,因为在运行时这是 JVM 寻求的签名 public "static" void main[] 作为入口点的方法开始执行代码。

    例子:

    public class Demo
    {
       public static void main(String... args) 
       {
          Demo d = new Demo();
    
          System.out.println("This static method is executed by JVM");
    
         //Now to call the static method Displ() you can use the below methods:
               Displ(); //By method name itself    
          Demo.Displ(); //By using class name//Recommended
             d.Displ(); //By using instance //Not recommended
       }
    
       public static void Displ()
       {
          System.out.println("This static method needs to be called explicitly");
       }
    } 
    

    输出:- 此静态方法由 JVM 执行 这个静态方法需要显式调用 这个静态方法需要显式调用 这个静态方法需要显式调用

    【讨论】:

      【解决方案4】:

      如果你在任何方法中应用static关键字,它被称为静态方法。

      1. 静态方法属于类而不是类的对象。
      2. 无需创建类实例即可调用的静态方法。
      3. 静态方法可以访问静态数据成员并且可以改变它的值。
      4. 仅使用类点静态名称的名称即可访问静态方法。 . .示例:Student9.change();
      5. 如果要使用类的非静态字段,则必须使用非静态方法。

      //改变所有对象的公共属性(静态字段)的程序。

      class Student9{  
       int rollno;  
       String name;  
       static String college = "ITS";  
      
       static void change(){  
       college = "BBDIT";  
       }  
      
       Student9(int r, String n){  
       rollno = r;  
       name = n;  
       }  
      
       void display (){System.out.println(rollno+" "+name+" "+college);}  
      
      public static void main(String args[]){  
      Student9.change();  
      
      Student9 s1 = new Student9 (111,"Indian");  
      Student9 s2 = new Student9 (222,"American");  
      Student9 s3 = new Student9 (333,"China");  
      
      s1.display();  
      s2.display();  
      s3.display();  
      }  }
      

      O/P:111 印度 BBDIT 222 美国BBDIT 333中国BBDIT

      【讨论】:

        【解决方案5】:

        静态方法应该在类上调用,实例方法应该在类的实例上调用。但这在现实中意味着什么?这是一个有用的例子:

        汽车类可能有一个名为 Accelerate() 的实例方法。如果汽车确实存在(已构建),您只能加速汽车,因此这将是一个实例方法。

        汽车类也可能有一个称为 GetCarCount() 的计数方法。这将返回创建(或建造)的汽车总数。如果没有构建汽车,此方法将返回 0,但它应该仍然可以被调用,因此它必须是一个静态方法。

        【讨论】:

          【解决方案6】:

          静态方法有两个主要用途:

          1. 用于不需要任何对象状态的实用程序或辅助方法。 由于不需要访问实例变量,因此具有静态 方法消除了调用者实例化对象的需要 只是调用方法。
          2. 对于所有人共享的状态 类的实例,如计数器。所有实例必须共享 相同的状态。仅使用该状态的方法应该是静态的 好吧。

          【讨论】:

            【解决方案7】:

            我想知道什么时候使用静态方法?

            1. static 方法的一个常见用途是访问static 字段。
            2. 但是您可以拥有static 方法,而无需引用static 变量。没有引用static变量的辅助方法可以在一些java类中找到,比如java.lang.Math

              public static int min(int a, int b) {
                  return (a <= b) ? a : b;
              }
              
            3. 另一个用例,我可以想到这些方法与synchronized 方法相结合是在多线程环境中实现类级锁定。

            假设我有一个带有几个 getter 和 setter 的类,一个或两个方法,并且我希望这些方法只能在类的实例对象上调用。这是否意味着我应该使用静态方法?

            如果你需要访问类的实例对象的方法,你的方法应该是非静态的。

            Oracle 文档page 提供了更多详细信息。

            并非所有实例和类变量和方法的组合都是允许的:

            1. 实例方法可以直接访问实例变量和实例方法。
            2. 实例方法可以直接访问类变量和类方法。
            3. 类方法可以直接访问类变量和类方法。
            4. 类方法不能直接访问实例变量或实例方法——它们必须使用对象引用。此外,类方法不能使用 this 关键字,因为没有 this 可以引用的实例。

            【讨论】:

            • 不能通过常规方法访问静态字段吗?那么这个A common use for static methods is to access static fields. 就不是论据了。
            【解决方案8】:

            静态方法是 Java 中无需创建类对象即可调用的方法。它属于这个类。

            当我们不需要使用实例调用方法时,我们使用静态方法。

            【讨论】:

              【解决方案9】:

              使用静态方法有一些正当理由:

              • 性能:如果您希望运行某些代码,并且不想实例化额外的对象来执行此操作,请将其放入静态方法中。 JVM 还可以优化静态方法很多(我想我曾经读过 James Gosling 声明你不需要 JVM 中的自定义指令,因为静态方法会一样快,但找不到源 - 因此这可能是完全错误的)。是的,它是微优化,可能不需要。而且我们程序员永远不会仅仅因为它们很酷而做不必要的事情,对吧?

              • 实用性:不要调用new Util().method(arg),而是调用Util.method(arg),或method(arg),使用静态导入。更简单,更短。

              • 添加方法:您确实希望 String 类具有 removeSpecialChars() 实例方法,但它不存在(也不应该存在,因为您的项目的特殊字符可能不同来自其他项目的),并且您无法添加它(因为 Java 有点理智),因此您创建了一个实用程序类,并调用 removeSpecialChars(s) 而不是 s.removeSpecialChars()。甜蜜。

              • 纯度:采取一些预防措施,您的静态方法将是pure function,也就是说,它唯一依赖的就是它的参数。数据输入,数据输出。这更易于阅读和调试,因为您无需担心继承问题。您也可以使用实例方法来做到这一点,但编译器会在静态方法方面为您提供更多帮助(通过不允许引用实例属性、覆盖方法等)。

              如果你想创建一个单例,你还必须创建一个静态方法,但是......不要。我的意思是,三思而后行。

              现在,更重要的是,为什么你不想创建一个静态方法?基本上,多态性消失了。您将无法覆盖该方法,也无法在接口中声明它 (Java 8 之前的版本)。您的设计需要很大的灵活性。此外,如果您需要 state,如果您不小心,最终会遇到很多 并发错误和/或瓶颈。

              【讨论】:

              • 这里列出了很多很好的理由说明静态何时有用。我能想到的另一件事是,为此类方法编写单元测试非常简单
              • @tetsuo 谢谢!你的解释很清楚,提供的理由很合逻辑,很有道理。
              • 我们程序员永远不会仅仅因为它们很酷而做不需要的事情,对吧? +1
              • 表示静态方法变成了全名函数stackoverflow.com/questions/155609/…
              • 我同意性能和实用性,但不同意纯度。静态方法可以修改类的静态成员(可能是私有的)。这可能很有用。例如,您可以有一个类似“static synchronized int allocateID() {return idNext++;}”的方法。事实上,就副作用而言,静态方法可以与非静态方法一样纯或不纯。
              【解决方案10】:

              在 Eclipse 中,您可以启用有助于检测潜在静态方法的警告。 (突出显示的行上方是我忘记突出显示的另一行)

              【讨论】:

                【解决方案11】:

                static 方法是一种不需要初始化任何对象即可调用的方法。你有没有注意到 static 在 Java 中的 main 函数中使用?程序执行从那里开始,没有创建对象。

                考虑以下示例:

                 class Languages 
                 {
                     public static void main(String[] args) 
                     {
                         display();
                     }
                
                     static void display() 
                     {
                         System.out.println("Java is my favorite programming language.");
                     }
                  }
                

                【讨论】:

                • 最佳答案
                【解决方案12】:

                可以使用静态方法

                • 不想对实例执行操作(实用方法)

                  正如本文上述几个答案中提到的,将英里转换为公里,或计算从华氏到摄氏的温度,反之亦然。通过这些使用静态方法的示例,它不需要在堆内存中实例化整个新对象。下面考虑

                  1. new ABCClass(double farenheit).convertFarenheitToCelcium() 
                  2. ABCClass.convertFarenheitToCelcium(double farenheit)
                  

                  前者为每个方法调用创建一个新的类足迹,Performance, Practical。示例如下:Math 和 Apache-Commons 库 StringUtils 类:

                  Math.random()
                  Math.sqrt(double)
                  Math.min(int, int)
                  StringUtils.isEmpty(String)
                  StringUtils.isBlank(String)
                  
                • 想要作为一个简单的函数使用。输入被显式传递,并将结果数据作为返回值。继承,对象实例化没有出现。 简洁易读

                注意: 很少有人反对静态方法的可测试性,但静态方法也可以测试!使用 jMockit,可以模拟静态方法。 可测试性。示例如下:

                new MockUp<ClassName>() {
                    @Mock
                    public int doSomething(Input input1, Input input2){
                        return returnValue;
                    }
                };
                

                【讨论】:

                  【解决方案13】:

                  实际上,我们在一个类中使用静态属性和方法,当我们想要使用程序的某些部分时,应该存在于我们的程序运行之前。我们知道,要操作静态属性,我们需要静态方法,因为它们不是实例变量的一部分。如果没有静态方法,操作静态属性非常耗时。

                  【讨论】:

                  • 在静态变量中保持状态是一件坏事,原因有很多——比如多线程安全、调试、数据封装..等静态方法如果它们是纯函数则可以(使用仅参数,不更改它们)。一个很好的例子是实用程序类,比如数学计算。
                  【解决方案14】:

                  仅在以下场景中定义静态方法:

                  1. 如果您正在编写实用程序类并且它们不应该被更改。
                  2. 如果方法没有使用任何实例变量。
                  3. 如果任何操作不依赖于实例创建。
                  4. 如果有一些代码可以很容易地被所有实例方法共享,则将该代码提取到静态方法中。
                  5. 如果您确定方法的定义永远不会被更改或覆盖。因为静态方法不能被覆盖。

                  【讨论】:

                  • 优点,但如果您想要将方法设为静态,则它们是必需的,而不是设为静态的理由。
                  • @Mohd 关于要求 5:您什么时候可以 100% 确定方法永远不会被更改或覆盖?在编写静态方法的那一刻,是不是总有一些未知因素无法考虑?
                  • “Utility-Classes”很难推理,坏事是迟早一切都开始“看起来像”一个实用程序(是的,我指的是那个“util”包臃肿,不可触碰且测试不佳),并且您的测试用例将需要更多工作(模拟静态工具是困难的)。优先选择对象。
                  • @Mohd 这个答案正是我想要的。我在多线程中使用静态方法遇到了很多问题。能否请您详细说明第 2 点、第 3 点(例如,为您竖起 100 个赞)
                  • 如果你要使用静态变量和方法,我认为应该发明一个“静态类”。
                  【解决方案15】:

                  静态方法和变量是 Java 中“全局”函数和变量的受控版本。其中方法可以作为classname.methodName()classInstanceName.methodName()访问,即静态方法和变量可以使用类名以及类的实例来访问。

                  类不能声明为静态(因为它没有意义。如果一个类声明为public,则可以从任何地方访问),内部类可以声明为静态。

                  【讨论】:

                    【解决方案16】:

                    静态方法不需要在对象上调用,即当您使用它时。示例:您的 Main() 是静态的,并且您没有创建对象来调用它。

                    【讨论】:

                    • 耶!看看我在谷歌搜索 Java noobie 问题时来到了哪里!这是一个小世界:-)
                    • @Deepak 确实是小世界 :)
                    【解决方案17】:

                    阅读 Misko 的文章后,我认为从测试的角度来看,static methods 是不好的。你应该改用factories(也许使用像Guice这样的依赖注入工具)。

                    我如何确保我只有一个东西

                    只有其中之一 “我如何确保我 只有一个东西”很好 回避了。你只实例化一个 您的单个 ApplicationFactory 主要的,因此,你只有 实例化所有的单个实例 你的单身人士。

                    静态方法的基本问题是它们是过程代码

                    静态方法的基本问题是 它们是程序代码。我没有 想法如何对程序代码进行单元测试。 单元测试假设我可以 实例化我的应用程序的一部分 隔离中。在实例化期间 我将依赖项与 模拟/友谊赛取代 真正的依赖。有程序 编程没有什么可以“接线”的 由于没有对象,代码 和数据是分开的。

                    【讨论】:

                    • 我不明白无法对程序代码进行单元测试的部分。您不只是使用静态方法以及作为“单元”的类来设置将正确输入映射到正确输出的测试用例吗?
                    • 您可以这样做来测试这些功能。但是在你想测试的其他类中使用这些静态方法时,我相信你不能伪造它们(模拟/友好)或任何东西,因为你不能实例化一个类。
                    • @Alfred:请查看PowerMock,它具有模拟静态方法的能力。在使用 PowerMock 的情况下,如果有的话,您会发现无法模拟的方法依赖项。
                    • 你可以使用 PowerMock 对静态进行单元测试,但是你很快就会发现你的 Permgen 空间已经用完了(完成了,得到了 T 恤),而且它仍然很讨厌。除非您知道(基于您自己在真正的 OO 语言方面至少十年的经验,而不是从 C 语言迁移),否则不要这样做。说真的,我见过的最糟糕的代码来自嵌入式开发人员对静态的使用,在大多数情况下,我们永远都被它困住了,添加更多代码只会让我们更加紧密地锁定在不可修改的单体中。松散耦合:不,可测试:几乎没有,可修改:从不。避免!
                    • 我可以理解测试依赖于静态状态的静态方法的困难。但是,当您测试 无状态 静态方法(如 Math.abs()Arrays.sort())时,即使是您可以将所有依赖项传递到的方法,我看不出这会如何阻碍单元测试。我想说一个简单的经验法则是:如果您有任何理由模拟程序逻辑,那么不要将它放在静态方法中。我从来没有理由嘲笑Arrays.sort()Math.abs()
                    【解决方案18】:

                    静态方法不与实例关联,因此它们不能访问类中的任何非静态字段。

                    如果方法不使用类的任何字段(或仅静态字段),您将使用静态方法。

                    如果使用了类的任何非静态字段,则必须使用非静态方法。

                    【讨论】:

                    • 清晰、简短和简单的答案。
                    【解决方案19】:

                    静态: Obj.someMethod

                    当您想要提供对方法的类级别访问权限时使用static,即在没有类实例的情况下该方法应该是可调用的。

                    【讨论】:

                      【解决方案20】:

                      如果您希望能够在没有类实例的情况下访问该方法,请使用静态方法。

                      【讨论】:

                      • 这并没有给出程序设计的任何理由。
                      【解决方案21】:

                      不,静态方法不与实例关联;他们属于这个阶级。静态方法是你的第二个例子;实例方法是第一个。

                      【讨论】:

                      • 如果不需要对象的状态操作,您应该使用静态方法。
                      【解决方案22】:

                      java 中的静态方法属于类(不是它的实例)。它们不使用实例变量,通常会从参数中获取输入,对其执行操作,然后返回一些结果。实例方法与对象相关联,顾名思义,可以使用实例变量。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2011-03-16
                        • 2013-07-11
                        • 2015-06-19
                        • 2014-06-04
                        • 1970-01-01
                        相关资源
                        最近更新 更多