Java 与类/对象相比,使用静态函数/变量有什么优势吗?

Java 与类/对象相比,使用静态函数/变量有什么优势吗?,java,code-formatting,Java,Code Formatting,在Robert C.Martin的《干净的代码》一书中,他清理了一个混乱的类,并以一个以这种方式由静态变量和静态函数组成的文件结束 public class PrimeGenerator{ private static int[] primes; private static ArrayList<Integer> multipleOfPrimes; public static int[] generate(int n){ primes =

在Robert C.Martin的《干净的代码》一书中,他清理了一个混乱的类,并以一个以这种方式由静态变量和静态函数组成的文件结束

public class PrimeGenerator{
    private static int[] primes; 
    private static ArrayList<Integer> multipleOfPrimes;

    public static int[] generate(int n){
        primes = new int[n];
        //call functions
        someFunctionThatModifiesPrimes()

        return primes;
    }

    private static void someFunctionThatModifiesPrimes(){
        //modify primes
        prime[x] = y;
    }
}
公共类素数生成器{
私有静态int[]素数;
私有静态数组列表多优先级;
公共静态int[]生成(int n){
素数=新整数[n];
//调用函数
修改sprimes()的某些函数
返回素数;
}
私有静态void someFunctionthatModifiedSprimes()函数{
//修改素数
素数[x]=y;
}
}
他写

请注意,它并不打算被实例化为对象。班级 只是一个可以声明和隐藏变量的有用范围

我的问题是,如果我能做到这一点,我为什么要做他所做的事:

public class PrimeGenerator{
    private int[] primes; 
    private ArrayList<Integer> multipleOfPrimes;

    public PrimeGenerator(int n){
        primes = new int[n];
    }

    public int[] generate(int n){
        //call functions
        someFunctionThatModifiesPrimes()

        return primes;
    }

    private void someFunctionThatModifiesPrimes(){
        //modify primes
        prime[x] = y;
    }
}
公共类素数生成器{
私有int[]素数;
私有数组列表多优先级;
公共素数生成器(int n){
素数=新整数[n];
}
公共int[]生成(int n){
//调用函数
修改sprimes()的某些函数
返回素数;
}
private void somefunction修改sprimes(){
//修改素数
素数[x]=y;
}
}
他的代码:

a) 不是线程安全的,当素数已经在生成(从多个线程调用)时调用“generate(int)”将导致此操作失败

b) 在一个全局变量完成运行后保留一个带有垃圾素数的全局变量,该变量在下次运行时将被覆盖

我能想到的唯一优点是它可能更快?即使这样,这也可以忽略不计


需要创建对象的代码是线程安全的,不保留垃圾数据,也不具有静态

我认为专注于一本书的叙述可能是这里的一个问题。实际上,这是关于从整个社区获得共识,以找出最佳编码实践。找出哪些在生产环境中工作得更好

有理由使用静态和非静态函数和变量。然而,我会犹豫是否使用“优势”这一语言

静态

如果您的纯逻辑与成员字段无关(即,成员字段从未被引用),那么最好是静态的。基本上,在这种情况下,您可能执行静态操作的原因是“关注点分离”,在某种程度上,如果您正在调试代码,或者尝试读取代码,并且您知道它是一个静态函数,那么您就不必担心成员

有时我使变量本身成为静态的,并使它们成为类的成员而不是对象。事实上,像这样的例子可能就是你的素数。素数不会从
PrimeGenerator
的一个实现更改为另一个实现,那么为什么要计算两次呢?你不会的。在计算完这些值之后,您可以以对象的所有实例化都可以访问或外部调用方可以静态访问的方式存储它们

我认为对线程安全的呼吁是一个巨大的失败。为什么它不能是线程安全的?您可以使用
synchronized(PrimeGenerator.class)
的任意组合,或使其线程安全

记住这一点,在全局/常量和范围限定为稀疏实例化的对象之间有一条细线。事实上,重温素数的例子,很容易看出它是如何被视为常数的(有无限个素数,但在计算上是有限的,这意味着我们可以得到完整的集合,因为我们定义它为完整的)。常数始终是静态的,只是因为没有理由为此浪费对象上的空间。所以,这本书的核心是,质数的例子实际上是一个非常糟糕的例子,作者在这本书中。那么,什么样的东西不是常数而是静态的呢

我马上想到的例子是a,但我将跳过它,因为根据我给出的反对素数的论点,试图证明它不是常数可能会更难。相反,如果你能容忍我一会儿的话,我将和一位女士一起去。考虑一个场景,一个类<代码> Foo正在进行某种工作,这些工作都严格地基于一些,称为“代码> Bar < /Cord>”,在尝试做一些工作之前,他们需要检查<代码> Bar < /代码>的状态。当然,您可能会执行类似于观察者模式的操作,并通知
Foo
的所有实例化,但随后您会在通知上浪费cpu周期(不管最终是多少),同时,每个实例化都需要存储该值,并与其他每个实例化相同。或者,您可以使用一个
publicstaticfinalatomicbooleanbar=newatomicboolean(),每个实例化只需要执行
Foo.bar.compareAndSet(预期值,newValue)

非静态

归根结底,这是一种偏好,但也有一些社区参与其中,还有一些效率问题。如果你真的不想使用静电,你绝对可以。您可能最终只是实例化一个类以从函数中获取一个值,然后转储刚刚在堆上创建的对象,但您可以这样做

我最近听到的一些反对静态的论点,我认为是一个更为严肃的论点(但仍然缺乏任何分量)的竞争者,就是代码是不可测试的。我要说,在制作界,JUnits是一件大事。可测试的代码很早就发现了bug,yada-yada-yada。那么这和静电有什么关系呢?嗯,开箱即用的框架(这是一个非常流行的框架)不支持