Java:何时使用静态方法

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

答案

一个经验法则:问自己 “即使尚未构建 Obj,调用此方法是否有意义?” 如果是这样,那肯定是静态的。

因此,在Car类中,您可能有一个double convertMpgToKpl(double mpg) ,该方法是静态的,因为即使没有人制造过 Car,也可能想知道 35mpg 转换为什么。但是void setMileage(double mpg) (设置一辆特定汽车的效率)不能是静态的,因为在构造任何汽车之前都无法调用该方法。

(顺便说一句,情况并非总是如此:您有时可能有一个涉及两个Car对象的方法,但仍希望它是静态的。例如Car theMoreEfficientOf( Car c1, Car c2 ) 。尽管可以将其转换为非 - static 版本,有些人会争辩说,由于没有哪个 “汽车” 更重要的 “特权” 选择,因此您不应该强迫调用者选择一个 Car 作为要在其上调用该方法的对象。但是,在所有静态方法中只有很小的一部分。)

仅在以下情况下定义静态方法:

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

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

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

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

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

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

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

现在,更重要的是, 为什么不想创建静态方法?基本上, 多态性超出了人们的视野 。您将无法覆盖该方法, 也无法在接口中 (Java 8 之前的版本)对其进行声明 。设计需要很多灵活性。另外,如果您需要state ,那么如果您不小心的话,将会遇到很多并发错误和 / 或瓶颈。

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

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

只拥有一种东西问题 “我如何确保自己只有一种东西” 被很好地绕开了。您仅实例化了主实例中的单个 ApplicationFactory,因此,您仅实例化了所有单例的单个实例。

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

静态方法的基本问题是它们是过程代码。我不知道如何对程序代码进行单元测试。单元测试假设我可以孤立地实例化我的应用程序的一部分。在实例化期间,我将依赖关系与模拟 / 友好关系连接起来,以替换实际的依赖关系。对于过程编程,由于没有对象,因此代码和数据是分开的,因此无需 “连接”。

class Languages 
 {
     public static void main(String[] args) 
     {
         display();
     }

     static void display() 
     {
         System.out.println("Java is my favorite programming language.");
     }
  }

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

不,静态方法与实例无关。他们属于阶级。静态方法是您的第二个示例。实例方法是第一个。

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();  
}  }

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

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

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

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

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

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