2013-09-28 44 views
1

https://stackoverflow.com/a/572550/1165790Java是否支持函数内部的静态变量来保持调用之间的值?

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

我也不想创建一个额外的参数,因为我不想负担外部调用的函数与实现细节。

我尝试了static关键字,但Java说它是非法修饰符。有没有直接的选择?如果不是,建议使用哪种解决方法?

我希望它具有函数作用域,而不是类作用域。

+0

您可以发布迄今为止已尝试的内容吗?你可以试试这样的: –

+0

Java有静态变量,只是它们的名字范围是类而不是方法。 (但是我怀疑你并没有完全理解Java存在范围的细微之处。) –

+0

将单实例变量声明为静态应该完全符合你的需要。看到你的代码会有所帮助。 –

回答

9

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

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


如果变量真的需要是静态的,那么你唯一的选择是让类范围。这就是你所拥有的一切。另一方面,如果这是某个递归方法调用中使用的工作变量,那么使其成为静态将意味着您的算法不可重入。例如,如果您尝试在多个线程上运行它,它将分崩离析,因为这些线程将尝试使用相同的静态...并相互干扰。在我看来,正确的解决方案将要么使用方法参数传递此状态。 (你也可以使用所谓的“线程本地”变量,但它们有一些显着的缺点......如果你担心200字节存储量的开销!)

+0

如果类被实例化了100次,并且我有一个变量的实例字段,那么每个实例化的对象都不会为变量分配内存(不管该方法是否被调用)? –

+0

所讨论的变量是一个int类型,所以如果只有一个客户端实际调用该方法,那么我们就浪费了2个字节* 99。我喜欢使用另一个带有附加参数的私有函数的解决方法。 –

5

你打算如何在不浪费内存的情况下保持呼叫间的价值?而消耗的内存可以忽略不计。

如果您需要存储状态,存储状态:只需使用静态字段。请确保您同步访问静态字段,以迎合分别从不同的线程同时调用的方法:


注意在多线程应用程序时使用静态变量建议。最简单的方法是将​​关键字添加到static方法,并将该方法作为使用该字段的唯一代码。鉴于该方法不经常被调用,这种方法将是完全可以接受的。

+0

<1%的实例化类的用户将使用该方法。我不想每次都为这个状态分配内存。我希望它具有函数范围,而不是类范围。 –

+1

每次实例化类时都不分配 - 所有实例之间共享一个静态成员字段。 Java对象是作为引用存储的,所以如果你在第一次使用方法时只分配实际的对象,那么在不使用方法的情况下,只有64位内存会被浪费(=整个程序运行时没有方法被调用一次)。 64b的内存比你存储代码的任何骇人的解决方法所需的内存少得多。 –

+0

@IdanArye大多数64位JVM使用32位引用。 –

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只存在于内存中一次,班里的所有实例访问它。

1

我同意波希米亚这是不可能的内存将是一个问题。此外,重复的问题:How do I create a static local variable in Java?

为了回应您对该方法添加额外参数以及公开实现细节的疑虑,希望补充说明有一种方法可以在不公开附加参数的情况下实现此目的。添加一个单独的私有函数,并让公共函数封装递归签名。我已经多次在函数式语言中看到过这个,但它当然也是Java中的一个选项。

你可以这样做:

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

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

虽然这可能不会与你的内存关心对付,因为我不认为Java编译器考虑尾递归优化。

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); 
     } 
    } 

}

+0

是的 - 几乎正是Alex刚刚在上面发布的。 –

2

也许你解决了你的问题,但这里有更多关于Java静态的细节。可以有静态类,函数或变量。

class myLoader{ 

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

} 

class myLoader{ 


    static void foo(){ 

    int x; 

    // do stuff 
    } 

    } 

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

+0

“如果你正在使用多线程编程,如果你的静态变量被同时访问,一定不要产生竞争条件。”......这是否意味着在所有线程中变量x将始终具有相同的值?我的意思是在所有线程中x的值相同? –

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); 
    ... 
} 
相关问题