Java是否支持函数内部的静态变量来保持调用之间的值?

时间:2013-09-28 02:09:45

标签: java

https://stackoverflow.com/a/572550/1165790

我想在Java中使用这个功能,因为我设计的函数很少被调用(但是当它被调用时,它会启动一个递归链),因此,我不想让变量成为实例字段每次实例化类时浪费内存。

我也不想创建一个额外的参数,因为我不想通过实现细节来加重对函数的外部调用。

我尝试了static关键字,但Java说这是一个非法的修饰符。有直接替代方案吗?如果没有,建议采用哪种解决方法?

我希望它具有功能范围,而不是类范围。

8 个答案:

答案 0 :(得分:10)

  

我希望它具有功能范围,而不是类范围。

然后你运气不好。 Java提供static(类作用域),实例和局部变量。没有Java等效于C的函数范围的static变量。


如果变量确实需要是静态的,那么你唯一的选择是使它成为类范围。这就是你所拥有的一切。

另一方面,如果这是在某些递归方法调用中使用的工作变量,那么将其设置为静态将意味着您的算法不可重入。例如,如果您尝试在多个线程上运行它,它将崩溃,因为线程将全部尝试使用相同的静态...并相互干扰。在我看来,正确的解决方案是使用方法参数传递此状态。 (你也可以使用一个所谓的“线程本地”变量,但它们有一些重要的下行...如果你担心大约200字节存储的开销!)

答案 1 :(得分:5)

如果没有“浪费内存”,你如何在通话之间保持价值?消耗的内存可以忽略不计。

如果你需要存储状态,存储状态:只需使用静态字段。


在多线程应用程序中使用静态变量时,建议小心:确保同步对静态字段的访问,以满足从不同线程同时调用的方法。最简单的方法是将synchronized关键字添加到static方法,并将该方法作为使用该字段的唯一代码。鉴于该方法很少被称为,这种方法是完全可以接受的。

答案 2 :(得分:2)

静态变量是类级变量。如果您在方法之外定义它,它将完全按照您的意愿运行。

参见文档:

Understanding instance and Class Members

Java中答案的代码......

public class MyClass {
    static int sa = 10;

    public static void foo() {
        int a = 10;

        a += 5;
        sa += 5;

        System.out.println("a = " + a + " sa = " + sa);
    }

    public static void main(String[] args) {
         for (int i = 0; i < 10; i++) {
             foo();
         }
    } 
}

Output: 
$ java MyClass
a = 15 sa = 15
a = 15 sa = 20
a = 15 sa = 25
a = 15 sa = 30
a = 15 sa = 35
a = 15 sa = 40
a = 15 sa = 45
a = 15 sa = 50
a = 15 sa = 55
a = 15 sa = 60

sa只在内存中存在一次,该类的所有实例都可以访问它。

答案 3 :(得分:2)

可能你的问题已经解决了,但这里有一些关于Java的静态细节。可以有静态类,函数或变量。

class myLoader{

static int x;
void foo(){
 // do stuff
}

}

class myLoader{


    static void foo(){

    int x;

    // do stuff
    }

    }

在第一种情况下,它充当类变量。你没有这种方式“浪费记忆”。您可以通过myLoader.x访问它 但是,在第二种情况下,方法本身是静态的,因此它本身属于类。在此方法中不能使用任何非静态成员。 单例设计模式将使用静态关键字仅对类进行一次实例化。 如果您使用的是多线程编程,请确保在同时访问静态变量时不会生成竞争条件。

答案 4 :(得分:1)

我同意波希米亚人的意见,记忆不太可能成为一个问题。另外,重复的问题:How do I create a static local variable in Java?

为了回应您关于向方法添加其他参数并公开实现细节的问题,我想补充说有一种方法可以实现这一点,而不会暴露额外的参数。添加一个单独的私有函数,并使用public函数封装递归签名。我已经多次在函数式语言中看到过这种情况,但它在Java中也是一种选择。

你可以这样做:

public int getResult(int parameter){
    return recursiveImplementation(parameter, <initialState>)
}

private int recursiveImplementation(int parameter, State state){
    //implement recursive logic
}

虽然这可能不会解决你对内存的担忧,因为我不认为java编译器会考虑尾部递归优化。

答案 5 :(得分:1)

在递归调用中在堆栈上设置的变量将是函数(帧)本地:

public class foo {
    public void visiblefunc(int a, String b) {
        set up other things;
        return internalFunc(a, b, other things you don't want to expose);          
    }                                                                              

    private void internalFunc(int a, String b, other things you don't want to expose) {
        int x; // a different instance in each call to internalFunc()                                                             
        String bar; // a different instance in each call to internalFunc()
        if(condition) {
            internalFunc(a, b, other things);
        }
    }

}

答案 6 :(得分:1)

有时可以通过简单地传递状态来保存状态。如果仅在内部进行递归,则委托给具有附加状态参数的私有方法:

public void f() { // public API is clean
    fIntern(0); // delegate to private method
}

private void fIntern(int state) {
    ...
    // here, you can preserve state between
    // recursive calls by passing it as argument
    fIntern(state);
    ...
}

答案 7 :(得分:0)

类似函数的小类怎么样?

static final class FunctionClass {
    private int state1;  // whichever state(s) you want.
    public void call() {
        // do_works...
        // modify state
    }

    public int getState1() {
        return state1;
    }
}

// usage:
FunctionClass functionObject = new FunctionClass();
functionObject.call(); // call1
int state1AfterCall1 = functionObject.getState1();
functionObject.call(); // call2
int state1AfterCall2 = functionObject.getState1();