https://stackoverflow.com/a/572550/1165790
我想在Java中使用这个功能,因为我设计的函数很少被调用(但是当它被调用时,它会启动一个递归链),因此,我不想让变量成为实例字段每次实例化类时浪费内存。
我也不想创建一个额外的参数,因为我不想通过实现细节来加重对函数的外部调用。
我尝试了static关键字,但Java说这是一个非法的修饰符。有直接替代方案吗?如果没有,建议采用哪种解决方法?
我希望它具有功能范围,而不是类范围。
答案 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();