如何在Java中只初始化一次本地变量

7
在C++中,以下代码:
#include <stdio.h>

static const char *init()
{
    printf("in init()\n");
}

static void func()
{
    static const char *str = init();
    printf("in func()\n");
}

int main()
{
    for (int i=0; i<10; ++i) {
        func();
    }
    return 0;
}

通过在初始化str的函数init()中打印跟踪信息,可以发现尽管 func() 被多次调用,但是 str 只被初始化一次。 运行时,总共有10行跟踪信息,一次为init()和10次为func()

在Java中,以下代码不应该做到同样的事情吗?

class test {
    private String init()
    {
        System.out.println("in init()");
        return "FOO";
    }

    private void func()
    {
        final String str = init();
        System.out.println("in func()");
    }

    public test()
    {
        for (int i=0; i<10; ++i) {
            func();
        }
    }

    public static main(String[] args)
    {
        test app = new test();
    }
}

运行时,会输出20行结果,每个init()func()各10行。 根据我对final变量的理解,我认为它应该是相同的行为。 所以我尝试了static final,但它无法编译(即使只是static)。 有没有办法实现这个功能? 我需要从我的类中的几个不同方法中调用一个耗时的初始化函数, 因此仅将变量移动到类范围内是行不通的。 此外,由于本地变量不会自动初始化,因此我不能在给变量赋值之前在变量周围包含if测试以检查是否为null。 我想我可以为我的类中的每个方法创建一个变量,但管理它将很麻烦。 最好的比喻就是如果我在每个方法中都包含以下内容:
public myfunc1()
{
    final String funcName = java.lang.Thread.currentThread().getStackTrace()[1].getMethodName();
}
public myfunc2()
{
    final String funcName = java.lang.Thread.currentThread().getStackTrace()[1].getMethodName();
}

在这种情况下,funcName在每个方法中得到一个唯一的值,但初始化是昂贵的。

你需要将字符串str和函数init()都声明为静态的。 - maverik
str 不能是 _static_,否则它将无法编译。 init() 不能是 _static_,因为它依赖于实例数据。 - Xaq
http://ideone.com/nHN6m9 - maverik
2个回答

5
以下是一个相当接近的近似值:
class test {

    private static final String str = init();

    private static String init()
    {
        System.out.println("in init()");
        return "FOO";
    }

    private void func()
    {
        System.out.println("in func()");
    }

    public test()
    {
        for (int i=0; i<10; ++i) {
            func();
        }
    }

    public static void main(String[] args)
    {
        test app = new test();
    }
}

请注意,str在类加载时初始化,而不是在第一次调用func()时初始化。

如果 init() 实际上需要上下文,则将在类构造或稍后初始化的成员将 str 初始化为 null,并且仅当 str == null 时才执行其长时间操作。 - CPerkins
不幸的是,这并没有提供答案,这就是为什么我在问题末尾提供了_myfunc1()和_myfunc2()的进一步例子。 - Xaq

2
final限定符通过一个方法调用使变量变为常量。如果您想要每个实例的单个值,可以在方法外使用实例成员变量。
private final String str = init();

private void func()
{
    System.out.println("in func()");
}

如果您希望在所有实例的所有方法调用中使用单个值,则可以在方法外部使用静态成员变量。
private static final String str = init();

private void func()
{
    System.out.println("in func()");
}

不是问题,每个多次调用的成员函数只需要单个初始化调用。请参考结尾的示例:myfunc1() 和 _myfunc2()_。 - Xaq
你也可以使用实例成员来实现这个功能 - 只需为每个方法使用不同的实例成员,就像在 C 中使用静态局部变量一样。 - Andy Thomas
我知道,正如问题所述,我正在寻找一种更容易管理的解决方案,而不是为我的类中的每个方法创建一个实例变量。 - Xaq
没有太多需要管理的。与C/C++的主要区别在于它的“位置”(以及选择是每个实例还是每个类)。如果您喜欢,可以将成员字段放置在每个方法之前。 - Andy Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接