使所有方法保持静态 [英] Making all methods static

查看:98
本文介绍了使所有方法保持静态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,有许多类包含处理数据的方法,可以计算和数据丰富。



我的问题是 - 如果类没有任何类级变量,我可以使类中的所有方法都是静态的吗?



我认为线程没有任何问题。



有任何后果吗?是否有任何性能优势,因为我没有实例化类?



示例类:

  A类{
公共对象findTheCar(String id){
Car car = new Car();
//做点什么
返车;
}
}

我打算将上面的内容更改为静态。

解决方案

一个经验法则:问问自己即使没有构建Obj,也可以调用此方法?如果是这样,那肯定是静态的。



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

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



虽然有一些正当理由可以使用静态方法:




  • 性能:如果你想要运行一些代码,并且不想实例化一个额外的对象来执行此操作,请将其推送进入静态方法。 JVM也可以很好地优化静态方法(我想我曾经读过James Gosling声明你不需要JVM中的自定义指令,因为静态方法会同样快,但找不到源 - 因此它可能是完全错误的)。是的,它是微优化,可能不需要。我们的程序员从不做不需要的事情只是因为它们很酷,对吗?


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


  • 添加方法:您真的希望类String具有removeSpecialChars()实例方法,但它不是那里(它不应该,因为你的项目的特殊字符可能与其他项目的不同),你不能添加它(因为Java是最低限度的),所以你创建一个实用程序类,并调用removeSpecialChars(s)而不是s.removeSpecialChars()。甜蜜。


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




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



现在,更重要的是,为什么你不想创建静态方法?基本上,多态性超出了窗口。您将无法覆盖该方法,也无法在界面中声明它。它从您的设计中获得了很大的灵活性。此外,如果您需要状态,如果您不小心,最终会出现大量并发错误和/或瓶颈。


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





  1. 如果您正在编写实用程序类,则不应更改它们。

  2. 如果方法未使用任何实例变量。

  3. 如果任何操作不依赖于实例创建。

  4. 如果有一些代码可以被所有实例方法轻松共享,请将该代码提取到静态方法中。

  5. 如果您确定永远不会更改或覆盖方法的定义。由于无法覆盖静态方法。

让我们更详细地讨论它:



优点:



静态成员/方法用于辅助类,例如Math或常量类。这有助于其他对象利用您不需要创建对象但使用类名调用的字符串或有用函数。示例 - 使用静态函数调用单例对象。



缺点:



静态成员是类的一部分,因此保留在内存中直到应用程序终止并且不能被垃圾收集。使用过多的静态成员有时会预测您无法设计产品并尝试使用静态/过程编程。它表示面向对象的设计受到损害。这可能导致内存溢出。如果你在Java中创建任何静态方法,也存在某些缺点,例如你不能覆盖Java中的任何静态方法,这样会使测试更难以用mock替换该方法。由于静态方法维护全局状态,因此它们可以在并发环境中创建难以检测和修复的细微错误。



要记住的事项:



静态变量将是类定义的一部分而不是堆。但是,当您知道将从多个位置访问对象时,静态变量很有用。访问静态资源不是线程安全的。您可能会在线程环境中获得奇怪/不可预测的结果。但是,如果您只读取静态值,那么使用线程就可以了。



Static Breaks封装的方式:



它们的技术实现是允许在所有类的实例中维护状态。问题是,这本质上不是OOP,因为它忽略了封装。如果某个类的任何实例都可以更改变量,则封装/信息隐藏背后的基本原则将完全丢失:对象不再完全控制其状态。它的状态现在依赖于基本上是全局的变量。我们知道的很糟糕。即使是私有静态变量也会在全局范围内维持状态,但只是限制其访问。对象的任何实例都可以更改静态变量,这会导致歧义,因为对象的单个实例不再能够控制自己的状态。状态变化可以在不知道依赖于有问题的状态的对象的情况下任意发生,因为当发生这种情况时对象可能无法正常工作。正如通常所说的那样,继承打破封装静态以更严厉的方式做到这一点:不仅暴露内部实现,还暴露内部状态。


在您的示例问题中:


正如您所提到的,该方法将会在多线程环境中使用,请考虑以下问题(修改您的代码):

  public Object findTheCar(String id){
Car car = null; //第2行
if(id!= null){
car = new Car();
}
//第6行
//做点什么

//
//第10行
返回车辆;
}




在上面:如果从两个执行线程,第一个线程在
第6行,第二个线程在第2行,这仍然是线程
safe。


因为:



局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。这也意味着所有本地原始变量都是线程安全的。



对象的本地引用有点不同。引用本身不共享。但是,引用的对象不存储在每个线程的本地堆栈中。所有对象都存储在共享堆中。如果本地创建的对象永远不会转义它创建的方法,那么它是线程安全的。实际上,只要这些方法或对象都不会将传递的对象提供给其他线程,您也可以将其传递给其他方法和对象。



存储对象成员在堆上与对象一起。因此,如果两个线程在同一对象实例上调用方法并且此方法更新对象成员,则该方法不是线程安全的。



线程安全检查:如果资源是在同一个线程的控制下创建,使用和处置,并且永远不会逃脱该线程的控制,该资源的使用是线程安全的。



来自: http://tutorials.jenkov.com/java-concurrency/thread-safety.html


In my application there are many classes which contain methods for processing data which can be computation and data enrichment.

My question is - if the class doesn't have any class level variables, can I make all the methods in the class static?

I suppose that there won't be any issues with threading.

Are there any consequences? Are there any performance advantage as I don't have to instantiate the class?

A sample class:

Class A{   
    public Object findTheCar(String id){    
        Car car= new Car();    
        //do something    
        return car;    
    }
}

I intend to change the above to static.

解决方案

One rule-of-thumb: ask yourself "does it make sense to call this method, even if no Obj has been constructed yet?" If so, it should definitely be static.

So in a class Car you might have a method double convertMpgToKpl(double mpg) which would be static, because one might want to know what 35mpg converts to, even if nobody has ever built a Car. But void setMileage(double mpg) (which sets the efficiency of one particular Car) can't be static since it's inconceivable to call the method before any Car has been constructed.

(Btw, the converse isn't always true: you might sometimes have a method which involves two Car objects, and still want it to be static. E.g. Car theMoreEfficientOf( Car c1, Car c2 ). Although this could be converted to a non-static version, some would argue that since there isn't a "privileged" choice of which Car is more important, you shouldn't force a caller to choose one Car as the object you'll invoke the method on. This situation accounts for a fairly small fraction of all static methods, though.)

Though there are some valid reasons to use static methods:

  • Performance: if you want some code to be run, and don't want to instantiate an extra object to do so, shove it into a static method. The JVM also can optimize static methods a lot (I think I've once read James Gosling declaring that you don't need custom instructions in the JVM, since static methods will be just as fast, but couldn't find the source - thus it could be completely false). Yes, it is micro-optimization, and probably unneeded. And we programmers never do unneeded things just because they are cool, right?

  • Practicality: instead of calling new Util().method(arg), call Util.method(arg), or method(arg) with static imports. Easier, shorter.

  • Adding methods: you really wanted the class String to have a removeSpecialChars() instance method, but it's not there (and it shouldn't, since your project's special characters may be different from the other project's), and you can't add it (since Java is minimally sane), so you create an utility class, and call removeSpecialChars(s) instead of s.removeSpecialChars(). Sweet.

  • Purity: taking some precautions, your static method will be a pure function, that is, the only thing it depends on is its parameters. Data in, data out. This is easier to read and debug, since you don't have inheritance quirks to worry about. You can do it with instance methods too, but the compiler will help you a little more with static methods (by not allowing references to instance attributes, overriding methods, etc.).

You'll also have to create a static method if you want to make a singleton, but... don't. I mean, think twice.

Now, more importantly, why you wouldn't want to create a static method? Basically, polymorphism goes out of the window. You'll not be able to override the method, nor declare it in an interface. It takes a lot of flexibility out from your design. Also, if you need state, you'll end up with lots of concurrency bugs and/or bottlenecks if you are not careful.

So define static methods in the following scenarios only:

  1. If you are writing utility classes and they are not supposed to be changed.
  2. If the method is not using any instance variable.
  3. If any operation is not dependent on instance creation.
  4. If there is some code that can easily be shared by all the instance methods, extract that code into a static method.
  5. If you are sure that the definition of the method will never be changed or overridden. As static methods can not be overridden.

Lets also discuss it in more details:

Advantages:

Static members/methods are used as in helper classes say like Math or in constants classes. which helps other objects to utilize Strings or useful functions for which you do not need to create object but invoked using Class name. Example – singleton objects are invoked using a static function.

Disadvantages:

Static members are part of class and thus remain in memory till application terminates and can’t be ever garbage collected. Using excess of static members sometime predicts that you fail to design your product and trying to cop of with static / procedural programming. It denotes that object oriented design is compromised. This can result in memory over flow. Also there are certain disadvantages if you make any method static in Java for example you can not override any static method in Java so it makes testing harder you can not replace that method with mock. Since static method maintains global state they can create subtle bug in concurrent environment which is hard to detect and fix.

Things to remember:

The static variable will be part of the class definition rather than on the heap. However static variables are useful when you know there will be accesses to the object from multiple places. Access to static resources is not thread safe. You might get weird/unpredictable results in a threaded environment. But if your only reading the static value then using threads for it is fine.

How Static Breaks encapsulation:

The technical implementation of them is to allow state to be maintained across all instances of a class. The problem is that this is intrinsically not OOP because it disregards encapsulation. If a variable can be altered by any instance of a class then the fundamental principle behind encapsulation/information hiding is lost entirely: An object is no longer in complete control of its state. Its state now relies on variables which are essentially global. Which we know is bad. Even private static variables maintain state at a global level but simply limit its access. Any instance of the object can alter the static variable which causes ambiguity as individual instances of the object no longer have control over their own state. State changes can arbitrarily happen without knowledge of an object which relies on that state which is problematic because the object may not work correctly when this happens. Much as it’s often said that "Inheritance breaks encapsulation" statics do this in a far more severe way: By not just exposing internal implementation but also by exposing internal state.

In Your Example Question:

As you mentioned, the method is going to be used in multithreaded invironment, think of the below problem (modified your code):

public Object findTheCar(String id) {
        Car car = null; //Line 2
        if (id != null) {
            car = new Car();
        }
        //Line 6
        // do something 

        //
        //Line 10
        return car;
    }

In the above: if this executed from two threads, and 1st thread is at line 6, and second thread is at line 2, still this will be thread safe.

Because:

Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe.

Local references to objects are a bit different. The reference itself is not shared. The object referenced however, is not stored in each threads's local stack. All objects are stored in the shared heap. If an object created locally never escapes the method it was created in, it is thread safe. In fact you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads.

Object members are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object members, the method is not thread safe.

Thread safety check: If a resource is created, used and disposed within the control of the same thread, and never escapes the control of this thread,the use of that resource is thread safe.

From: http://tutorials.jenkov.com/java-concurrency/thread-safety.html

这篇关于使所有方法保持静态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆