gpt4 book ai didi

java - 从外部方法访问变量

转载 作者:行者123 更新时间:2023-12-04 09:14:18 25 4
gpt4 key购买 nike

我正在研究 Java 中的内部类,我遇到了与外部方法中的变量引用有关的问题。比如我有一个源码可以统计多少次compareTo()在排序期间调用方法:

        int counter = 0;
Date[] dates = new Date[100];
for(int i = 0; i < dates.length; i++)
{
dates[i] = new Date()
{
public int compareTo(Date other)
{
counter++;
return super.compareTo(other);
}
};
}
Arrays.sort(dates);
System.out.println(counter + " comparisons");
执行源码可以看到 counter++的使用存在错误.为了解决这个问题,有人告诉我应该这样改:
        int[] counter = new int[1];
Date[] dates = new Date[100];
for(int i = 0; i < dates.length; i++)
{
dates[i] = new Date()
{
public int compareTo(Date other)
{
counter[0]++;
return super.compareTo(other);
}
};
}
Arrays.sort(dates);
System.out.println(counter[0] + " comparisons");
我很困惑这两个代码之间有什么区别,这个错误的原因和解决方案是什么?

最佳答案

您正在创建一个可以“旅行”的代码片段。 {} 中的代码属于您的new Date()声明没有在你写的地方运行;它附加到您制作的这个日期对象上,并与它一起使用。此日期对象可以旅行:它可以存储在字段中。也许它在 18 天后运行,在一个完全不同的线程中。 VM 不知道,因此需要为发生这种情况做好准备。
所以让我们说它确实:你的“计数器”变量会发生什么?
通常,局部变量存储在“堆栈上”并在方法退出时被销毁。但在这种情况下,我们将销毁您的旅行代码仍然可以访问的变量,那么这意味着什么,从现在开始 18 天,当您的日期 compareTo 代码被调用时?
假设虚拟机默默地“升级”变量;它不是像往常一样在堆栈上声明它,而是在堆上声明它,以便变量可以在方法退出时继续存在。
好的。如果在另一个线程中调用 compareTo 怎么办?现在是否可以将局部变量标记为“ volatile ”?是否可以声明,在 java 中,甚至局部变量也可能显示竞争条件?
这是一个判断性的电话;由语言设计者决定。
Java 的语言设计者决定反对静默升级到堆,并反对允许本地人可能受到多线程访问。
因此,您在任何可以“旅行”* 的代码块中访问的任何局部变量都必须声明为 final。或 [B] 表现得好像它本来可以那样,在这种情况下,java 会默默地为你完成它。
变化是counter ,变量本身,不变在第二个片段中:它是对数组的引用,并且该引用永远不会改变。实际上,您已经自己添加了间接级别和堆访问:堆上存在数组。
对于它的值(value),我发现 AtomicX 的使用更具可读性。因此,如果您需要一个可在旅行代码中修改的 int,请不要执行 new int[1] ;做new AtomicInteger .如果您需要可修改的字符串,请使用 new AtomicReference<String>() ,而不是 new String[1] .
注意:是的,在这个特定的代码中,即使是排序操作,在这个方法中也只使用了 counter 变量,并且一旦这个方法结束,counter var 就可以消失,但是编译器并没有做那种非常深入的事情为了弄清楚这一点,它使用了更简单的规则:想在“旅行”代码中从外部 scipe 访问本地变量吗?不允许 - 除非它(有效)是最终的。
*) 旅行代码是方法本地或匿名类定义中的任何内容,以及 lambda 中的任何内容。所以:


void method() {
class MethodLocalClassDef {
// anything here is considered 'travelling'
}

Object o = new Object() {
// this is an anonymous class def,
// and anything in here is 'travelling'
};

Runnable r = () -> {
// this is a lambda, and considered 'travelling'
};
}

关于java - 从外部方法访问变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63286968/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com