Java:何时使用静态方法


911

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

例如

Obj x = new Obj();
x.someMethod

要么

Obj.someMethod

(这是静态方式吗?)

我很困惑!

Answers:


1458

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

因此,在一个类中,Car您可能有一个方法:

double convertMpgToKpl(double mpg)

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

void setMileage(double mpg)

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

(顺便说一句,情况并非总是如此:您有时可能有一个涉及两个Car对象的方法,但仍然希望它是静态的。例如:

Car theMoreEfficientOf( Car c1, Car c2 )

尽管可以将其转换为非静态版本,但有人会认为,由于没有“特权”选择Car更为重要,因此您不应强迫调用者选择一个Car作为要调用的对象。方法。不过,这种情况仅占所有静态方法的一小部分。)


325
这里有一些很好的例子。但是,我想补充一下,当您知道实例之间的某些内容不会改变时,“静态”通常很有价值。如果是这样,我真的会考虑“单一责任原则”,这意味着一个班级应该具有一种责任,因此只有一个改变的理由。我觉得应该考虑将“ ConvertMpgToKpl(double mpg)”功能和类似方法移到自己的类中。汽车对象的目的是允许汽车实例化,而不是提供它们之间的比较。这些应该在班级外部。
扎克·詹森

34
我想我更喜欢这种方法Car#isMoreEfficientThan(Car)。它的优点是,您平局返回的那辆车不是随心所欲的。通过方法的标题可以明显看出,领带中返回的是什么。
Cruncher 2014年

5
我也会在创建使用某些外部资源(文件系统,数据库等)的静态方法时保持谨慎,这种静态类型可能会使测试使用方法变得可怕。我个人试图将静态变量保留在“实用程序”领域。
赛斯M.

7
实际上,应将其实现为Comparator
Dogweather

3
@ B1KMusic当然。我所说的“哪辆车被平局归还”是“对被叫车的正确映射,对经过的车的错误映射”。没有任何歧义。
Cruncher

538

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

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

45
好点,但他们的要求,如果你想要做的方法静态的,没有理由让一个。
tetsuo 2013年

4
关于要求5的@Mohd:什么时候可以100%确定永远不会更改或覆盖方法?编写静态方法时,难道不总是存在无法忽略的未知因素吗?
PixelPlex

8
“实用程序类”很难推论,不好的是,迟早一切都会开始看起来像一个实用程序(是的,我指的是那种“ util肿”,无法触及且测试不良的“实用程序”包),并且您的测试用例将需要更多的工作(模拟静态工具很困难)。首先优先选择对象。
塞尔吉奥

2
@Mohd这个答案正是我想要的。在多线程中使用静态方法时,我遇到了很多问题。您能否再详细说明第2点,第3点(例如100个大拇指)
Prakash Pandey

我认为如果要使用静态变量和方法,应该发明一个“静态类”。
罗伯特·罗查

182

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

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

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

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

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

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

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


1
这里列出了很多关于何时使用静态变量的充分理由。我还能想到的是,为这种方法编写单元测试非常简单
nilesh

@tetsuo谢谢!您的解释非常清楚,提供的原因非常合乎逻辑并且很有道理。
Deniss M.

3
而且我们程序员永远不会仅仅因为它们很酷就做不需要的事情,对吗?+1
Scaramouche

就是说静态方法变成了一个全称的函数stackoverflow.com/questions/155609/…–
Ivanzinho

我同意性能和实用性,但不同意纯度。静态方法可以修改类的静态成员(可以是私有的)。这可能很有用。例如,您可以使用类似“静态同步intallocateID(){返回idNext ++;}”的方法。实际上,就副作用而言,静态方法可能与非静态方法一样纯或不纯。
亚当·格恩·凯恩

42

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

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

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

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

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


20
我不了解无法对程序代码进行单元测试的部分。您不只是使用静态方法以及将类作为“单元”来设置将正确的输入映射到正确的输出的测试用例吗?
tjb 2012年

2
您可以这样做来测试这些功能。但是,在要测试的其他类中使用这些静态方法时,我相信您不能伪造它们(嘲笑/友好)或其他任何东西,因为您无法实例化一个类。
2012年

4
@Alfred:请看一下具有模拟静态方法功能的PowerMock。使用PowerMock,在少数情况下(如果有),您会发现无法模拟的方法依赖项。
卡莱斯·萨拉

7
您可以使用PowerMock对静态单元进行单元测试,但是很快您会发现自己用完了Permgen的空间(这样做之后,得到了T恤),而且它仍然很讨厌。除非您了解(至少基于自己在真正的OO语言上的十年经验,而不是从C迁移而来),否则不要这样做。严重的是,我见过的最糟糕的代码来自嵌入式开发人员对静态函数的使用,并且在大多数情况下,我们永远都无法使用它,而添加更多代码则将我们更加紧密地锁定在不可修改的整体中。松耦合:不,可测试:勉强,可修改:永不。避免!
user1016765 2014年

14
我可以理解测试依赖于静态状态的静态方法的困难。但是,当您测试无状态静态方法(例如Math.abs()或)时Arrays.sort(),甚至可以将所有依赖项传递给的方法,我也看不到这会如何阻碍单元测试。我想说一个简单的经验法则是:如果您有任何理由要模仿过程逻辑,则不要将其放在静态方法中。我从来没有理由嘲笑Arrays.sort()Math.abs()
安迪

36

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.");
     }
  }

最佳答案实际上
Yahya

20

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


12

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


1
如果不需要对象的状态操作,则应使用静态方法。
MastAvalons,

11

如果通过任何方法应用static关键字,则称为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();  
}  }

运/输:111印度BBDIT 222美国BBDIT 333中国BBDIT


10

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

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

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


1
清晰,简短的答案。
乔西

8

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

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

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


6

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


将状态保持在静态变量中是一件不好的事,原因有很多-例如多线程安全,调试,数据封装等。如果静态方法是纯函数,则可以使用静态方法(仅使用参数,而无需更改它们)。一个很好的例子是实用程序类,例如数学计算。
弗拉基米尔·德米列夫

5

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


29
这并没有为程序设计提供任何理由。
adamjmarkham 2012年

4

静态的: Obj.someMethod

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


4

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


1
好极了!看看我在搜索Java noobie问题时来到哪里!这是一个很小的世界:-)
Deepak

1
@Deepak小世界的确是:)
Vaishak Suresh

4

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

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


3

如果可以使用静态方法

  • 一个不想对实例执行操作(实用程序方法)

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

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

    前者为每个方法调用(性能,实用)创建了一个新的类足迹。示例包括下面的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;
    }
};

3

静态方法是Java中可以在不创建类对象的情况下调用的方法。它属于该类。

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


2

我想知道何时使用静态方法?

  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文档页面提供了更多详细信息。

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

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

我们不能通过常规方法访问静态字段吗?那么这A common use for static methods is to access static fields.不是一个论点。
parsecer

2

静态方法有两个主要目的:

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

1

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

日食设置


0

每当您不想在代码中创建对象来调用方法时,只需将该方法声明为静态方法即可。由于静态方法不需要调用实例,但是这里要注意的是并不是所有静态方法都可以由JVM自动调用。此特权仅由Java中的main()“ public static void main [String ... args]”方法享有,因为在运行时,这是JVM寻求Signature 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执行此静态方法需要显式调用此静态方法需要显式调用此静态方法需要显式调用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.