Java:何时使用静态方法

KP6*_*P65 868 java static-methods

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

例如

Obj x = new Obj();
x.someMethod
Run Code Online (Sandbox Code Playgroud)

要么

Obj.someMethod
Run Code Online (Sandbox Code Playgroud)

(这是静态方式吗?)

我很困惑!

not*_*eti 1397

一个经验法则:问问自己"即使没有构建Obj,这个方法也有意义吗?" 如果是这样,那肯定是静态的.

所以在一个类中Car你可能有一个double convertMpgToKpl(double mpg)静态的方法,因为人们可能想知道35mpg转换成什么,即使没有人建造过汽车.但是void setMileage(double mpg)(设置一个特定Car的效率)不能是静态的,因为在构建任何Car之前调用该方法是不可思议的.

(顺便说一下,反过来并不总是这样:你有时可能有一个涉及两个Car对象的方法,但仍然希望它是静态的.例如Car theMoreEfficientOf( Car c1, Car c2 ).虽然这可以转换为非静态版本,但有些人会认为,因为那里不是一个"特权"选择,其中Car更重要,你不应该强迫调用者选择一个Car作为你将调用方法的对象.这种情况只占所有静态方法的一小部分,虽然.)

  • 这里有一些很好的例子.但是,我想补充说,当您知道某些事情不会在实例之间发生变化时,"静态"通常很有价值.如果是这种情况,我会真正考虑"单一责任原则",这意味着一个班级应该有一个责任,因此只有一个改变的理由.我觉得应该考虑将"ConvertMpgToKpl(双mpg)"函数和类似的方法移动到他们自己的类中.汽车对象的目的是允许汽车的实例化,而不是在它们之间进行比较.那些应该是班级的外部. (308认同)
  • 我想我宁愿用'Car#isMoreEfficientThan(Car)`这个方法.它的优势在于您在领带中返回的汽车不是任意的.通过方法的标题显而易见的是领带中返回的内容. (34认同)
  • 实际上,它应该作为[Comparator](http://www.tutorialspoint.com/java/java_using_comparator.htm)实现. (7认同)
  • 我还要小心创建一个使用一些外部资源(文件系统,数据库等)的静态方法,这种类型的静态可能会使测试消费方法变得非常糟糕.我个人试图将静态保持在"效用"的范围内. (5认同)
  • @ B1KMusic当然.我的意思是"哪条车返回领带"是"真正映射到被叫汽车,虚假地图到过去的汽车".它毫不含糊. (2认同)
  • -1 示例方法`double convertMpgToKpl(double mpg)` 和`Car theMoreEfficientOf( Car c1, Car c2 )` 显然不是Car 类的方法。而今天,在 2017 年,在 DI 和松耦合的时代,这些方法即使在另一个类中也不应该是静态的。 (2认同)
  • 与一些评论相反,我真的很欣赏第二个例子.虽然它可能不是实际使用中最好的方法,但它帮助我更好地理解了问题的答案. (2认同)

小智 515

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

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

  • 好点,但如果你想要*使方法静态,而不是制作方法的理由,它们就是要求. (38认同)
  • "实用程序类"很难推理,坏的是迟早所有东西都开始"看起来像'一个实用程序(是的,我指的是那个膨胀,不可触及且测试不良的"util"包),并且您的测试用例将需要更多工作(模拟静态工具是HARD).首先选择对象. (7认同)
  • @Mohd关于要求5:你什么时候能100%确定一个方法永远不会被改变或覆盖?在您编写静态方法时,是否始终存在未知因素? (4认同)
  • @Mohd这个答案正是我要找的.我在多线程中使用静态方法遇到了很多问题.能否详细说明第2,3点(示例100竖起大拇指) (2认同)

tet*_*suo 168

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

  • 性能:如果您希望运行某些代码,并且不希望实例化额外的对象,请将其推送到静态方法中.JVM也可以优化静态方法(我想我曾经读过James Gosling声明你不需要JVM中的自定义指令,因为静态方法会同样快,但找不到源 - 因此它可能是完全错误的).是的,它是微优化,可能不需要.而且我们程序员从不做不需要的东西只是因为它们很酷,对吧?

  • 实用性:而不是呼叫new Util().method(arg),呼叫Util.method(arg)method(arg)静态导入.更简单,更短.

  • 添加方法:你真的希望类String有一个removeSpecialChars()实例方法,但它不存在(它不应该,因为你的项目的特殊字符可能与其他项目不同),你不能添加它(因为Java)有点理智,所以你创建一个实用程序类,而removeSpecialChars(s)不是调用s.removeSpecialChars().甜.

  • 纯度:采取一些预防措施,你的静态方法将是一个纯函数,也就是说,它唯一依赖的是它的参数.数据输入,数据输出.这更容易阅读和调试,因为您没有担心继承怪癖.您也可以使用实例方法来完成它,但编译器将使用静态方法帮助您(通过不允许引用实例属性,重写方法等).

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

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

  • *我们的程序员从不做不需要的东西只是因为它们很酷,对吧?*+1 (3认同)
  • 这里列出了很多关于静态何时有用的充分理由。我能想到的另一件事是,为此类方法编写单元测试非常简单 (2认同)

Alf*_*red 40

在阅读了Misko的文章后,我认为从测试的角度看静态方法是不好的.你应该有工厂(可能使用像Guice这样的依赖注入工具).

我怎样才能确保我只有一件东西

只有一个东西"如何确保我只有一个东西"的问题很好地回避了.您只在main中实例化一个ApplicationFactory,因此,您只实例化所有单例的单个实例.

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

静态方法的基本问题是它们是过程代码.我不知道如何对程序代码进行单元测试.单元测试假设我可以单独实例化我的应用程序.在实例化期间,我使用mocks/friendlies连接依赖项,这取代了真正的依赖项.使用程序编程没有任何"连线",因为没有对象,代码和数据是分开的.

  • 我不明白关于无法对程序代码进行单元测试的部分.您是否只是使用静态方法和类作为"单位"来设置将正确输入映射到正确输出的测试用例? (19认同)
  • 我可以理解测试依赖于静态的静态方法的难度.但是当你测试*无状态*静态方法如`Math.abs()`或`Arrays.sort()`时,即使你可以*将所有依赖项传递给*的方法,我也看不出它会如何阻碍单位测试.我想说一个简单的经验法则是:如果你有任何理由嘲笑程序逻辑,那么不要把它放在静态方法中.我从来没有理由嘲笑`Arrays.sort()`或`Math.abs()`. (13认同)
  • 你可以使用PowerMock对静态单元进行单元测试,但是你很快就会发现你的Permgen空间用完了(做完了,得到了T恤),而且它仍然很讨厌.除非你知道(根据你自己在真正的OO语言中至少十年的经验,不是从C迁移),否则不要这样做.说真的,我见过的最糟糕的代码来自嵌入式开发人员对静态的使用,在大多数情况下,我们一直坚持使用它,并且添加更多代码只是将我们锁定在不可修改的整体中更加紧密.松耦合:不,可测试:几乎不可修改:永远不会.避免! (7认同)
  • @Alfred:请查看[PowerMock](http://code.google.com/p/powermock/),它能够模拟静态方法.使用PowerMock的情况很少,如果有的话,您可以找到无法模拟的方法依赖项. (4认同)
  • 你可以这样做来测试这些功能.但是当你想要测试的其他类中使用这些静态方法时,我相信你不能伪造它们(模拟/友谊)或任何东西,因为你无法实例化一个类. (2认同)

小智 34

static方法是要被初始化一个类型的方法,其不需要任何对象为它被调用.您是否注意到在Java static中的main函数中使用了什么?程序执行从那里开始,没有创建对象.

请考虑以下示例:

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

     static void display() 
     {
         System.out.println("Java is my favorite programming language.");
     }
  }
Run Code Online (Sandbox Code Playgroud)


Kev*_*tre 18

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


duf*_*ymo 11

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


Ind*_*234 11

如果对任何方法应用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();  
}  }
Run Code Online (Sandbox Code Playgroud)

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


Car*_*ten 8

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

如果方法不使用类的任何字段(或仅静态字段),则可以使用静态方法.

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


Cha*_*man 7

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

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

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


小智 6

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


Jam*_*mey 5

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

  • 这并没有给出程序设计的任何理由. (28认同)

Fin*_*arr 5

静止的: Obj.someMethod

使用static时要提供一种方法,即其中的方法应该是可调用无类的实例类级别的访问。