https://stackoverflow.com/a/572550/1165790
我想在 Java 中使用此功能,因为我正在设计的函数很少被调用(但是当它被调用时,它会启动一个递归链),因此,我不想将变量作为实例字段来浪费内存每次实例化类时。
我也不想创建额外的参数,因为我不想用实现细节给函数的外部调用增加负担。
我尝试了 static 关键字,但 Java 说它是非法修饰符。有没有直接的替代方案?如果没有,推荐什么解决方法?
我希望它具有函数范围,而不是类范围。
https://stackoverflow.com/a/572550/1165790
我想在 Java 中使用此功能,因为我正在设计的函数很少被调用(但是当它被调用时,它会启动一个递归链),因此,我不想将变量作为实例字段来浪费内存每次实例化类时。
我也不想创建额外的参数,因为我不想用实现细节给函数的外部调用增加负担。
我尝试了 static 关键字,但 Java 说它是非法修饰符。有没有直接的替代方案?如果没有,推荐什么解决方法?
我希望它具有函数范围,而不是类范围。
我希望它具有函数范围,而不是类范围。
那你就不走运了。Java 提供static
(类作用域)、实例和局部变量。没有与 C 的函数范围static
变量等效的 Java。
如果变量确实需要是静态的,那么您唯一的选择就是使其具有类作用域。这就是你所拥有的。
另一方面,如果这是在某些递归方法调用中使用的工作变量,那么将其设为静态将意味着您的算法不可重入。例如,如果您尝试在多个线程上运行它,它将分崩离析,因为线程都将尝试使用相同的静态...并相互干扰。在我看来,正确的解决方案是使用方法参数传递此状态。(您也可以使用所谓的“线程本地”变量,但它们有一些明显的缺点......如果您担心大约 200 字节的存储开销!)
你将如何在不“浪费内存”的情况下在调用之间保持一个值?并且消耗的内存可以忽略不计。
如果需要存储状态,存储状态:只需使用静态字段即可。
在多线程应用程序中使用静态变量时要小心:确保同步访问静态字段,以适应从不同线程同时调用的方法。最简单的方法是将synchronized
关键字添加到static
方法中,并将该方法作为使用该字段的唯一代码。考虑到该方法很少被调用,这种方法是完全可以接受的。
静态变量是类级别的变量。如果您在方法之外定义它,它将完全按照您的意愿行事。
请参阅文档:
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 在内存中只存在一次,类的所有实例都可以访问它。
我同意波西米亚的观点,记忆不太可能成为问题。另外,重复的问题:如何在 Java 中创建静态局部变量?
为了回应您对向方法添加附加参数并公开实现细节的担忧,想补充一点,有一种方法可以在不公开附加参数的情况下实现这一点。添加一个单独的私有函数,并让公共函数封装递归签名。我已经在函数式语言中多次看到过这种情况,但它在 Java 中当然也是一种选择。
你可以做:
public int getResult(int parameter){
return recursiveImplementation(parameter, <initialState>)
}
private int recursiveImplementation(int parameter, State state){
//implement recursive logic
}
尽管这可能不会解决您对内存的担忧,因为我认为 java 编译器不会考虑尾递归优化。
可能你的问题已经解决了,但这里有更多关于 Java 中静态的细节。可以有静态类、函数或变量。
class myLoader{
static int x;
void foo(){
// do stuff
}
}
相对
class myLoader{
static void foo(){
int x;
// do stuff
}
}
在第一种情况下,它充当类变量。您不必以这种方式“浪费内存”。您可以通过 myLoader.x 访问它。但是,在第二种情况下,方法本身是静态的,因此它本身属于该类。不能在此方法中使用任何非静态成员。单例设计模式将使用 static 关键字仅将类实例化一次。如果您正在使用多线程编程,请确保在同时访问您的静态变量时不要生成竞争条件。
在递归调用中设置在堆栈上的变量将是函数(帧)本地:
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);
}
}
}
有时状态可以通过简单地传递来保存。如果仅在内部需要递归,则委托给具有附加状态参数的私有方法:
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);
...
}
一个类似函数的小类怎么样?
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();