简体   繁体   English

难以理解为什么我不能在方法外部修改变量?

[英]Trouble understanding why I cannot modify variable outside a method?

public class test {

    public static void main(String[] args) throws Exception {

        final int num = 111;

        new Thread() {
            @Override
            public void run() {
                num = 222;
            }
        }.start();

    }
}

I want to change the value of num however I can only do that if I set it to final which would not let me modify this. 我想更改num的值,但是只有将其设置为final ,我才能这样做,但不允许我对其进行修改。 In other languages such as C we can use pointers but Java cannot? 在其他语言(例如C)中,我们可以使用指针,但是Java不能吗?

Java has neither closure nor pointers. Java既没有闭包也没有指针。

A solution would be to make the num static in the class : 一种解决方案是使num在类中为静态:

public class test {
    static int num = 111;
    public static void main(String[] args) throws Exception {
        new Thread() {
            @Override
            public void run() {
                num = 222;
            }
        }.start();
    }
}

Another solution would be to use an object like AtomicInteger . 另一种解决方案是使用AtomicInteger之类的对象。 You can't change the value of the variable but you can change the content of the value : 您不能更改变量的值,但是可以更改值的内容:

public class test {
    public static void main(String[] args) throws Exception {
        final AtomicInteger num = new AtomicInteger(111);
        new Thread() {
            @Override
            public void run() {
                num.set(222);
            }
        }.start();
    }
}

Why this isn't allowed 为什么不允许这样做

main is a method. main是一种方法。 As with other programming languages, when a method returns, all of the variables declared in its body go out of scope, and accessing them has undefined behavior. 与其他编程语言一样,当方法返回时,在其主体中声明的所有变量都超出范围,并且对其进行访问具有未定义的行为。 Under some circumstances, the memory location where they used to be will no longer be valid. 在某些情况下,它们以前所在的存储位置将不再有效。

Obviously this is a problem. 显然这是一个问题。 If you try to change num after main has returned, you might overwrite a portion of the stack that doesn't belong to num anymore. 如果在main返回后尝试更改num ,则可能会覆盖堆栈中不再属于num Java's response to this difficult situation is to introduce restrictions on how you can share variables: they must be final. Java对这种困难情况的回应是对共享变量的方式施加了限制:它们必须是最终的。 Java can then safely locate them in such a way that reading them will produce consistent results even after the function has returned. 然后,Java可以安全地定位它们,以使即使在函数返回后也可以读取一致的结果。

The C equivalent to this problem is storing and using the address of a local variable outside of its scope, something that all C programmers are taught to never do. 等同于此问题的C语言是在其范围之外存储和使用局部变量的地址,这是所有C程序员都从未教过的。

To get around it, declare num as a member of test , create an instance, and pass that to it. 为了解决这个问题,请将num声明为test的成员,创建一个实例,并将其传递给它。 This removes the dependancy on a local variable, and thus removes the final restriction. 这消除了对局部变量的依赖,从而消除了final限制。

public class test
{
    int num = 111;

    public static void main(String[] args) throws Exception
    {
        test t = new test();
        (new Thread(t) {
            test mytest;
            Thread(test t)
            {
                mytest = t;
            }

            @Override
            public void run() {
                mytest.num = 222;
            }
        }).start();
    }
}

Well, you can access it if you declare variable outside the function. 好吧,如果您在函数外部声明变量,则可以访问它。 Like this: 像这样:

public class test {

private static int num = 111;

    public static void main(String[] args) throws Exception {

        new Thread() {
            @Override
            public void run() {
                num = 222;
            }
        }.start();

    }
}

You are creating new Thread() { class as inner class. 您正在创建new Thread() {类作为内部类。 You can't access outer class variables without declaring them as final. 您必须将外部类变量声明为final才能访问它们。

You can't change final variable references. 您不能更改最终变量引用。

There are two ways you can do this, 有两种方法可以做到这一点,

1) Make num as static 1)将num设为静态

2) Wrap num inside an object (You can update state of the object even though you define reference as final). 2)在对象内包装num(即使将引用定义为final,也可以更新对象的状态)。

NOTE: Both are not thread safe. 注意:两者都不是线程安全的。

Yep you can't win here! 是的,您不能在这里赢! You need to set it final to be able to access it, but then you will not be able to modify it. 您需要将其最终设置为可以访问它,但之后将无法对其进行修改。 You'll need to look at a different approach. 您需要考虑另一种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM