我们知道只能在匿名类中访问最终的局部变量,这里有一个很好的理由:为什么在匿名类中只能访问最终变量?.
但是,我发现如果变量是封闭类的成员字段,匿名类仍然可以访问非final变量:如何从匿名类内部访问封闭的类实例变量?
我很迷惑.我们确保只能在匿名类中访问最终的局部变量,因为我们不希望变量在匿名类和本地函数之间不同步.如果我们尝试访问匿名类中的非最终封闭类成员,则同样的理由应该适用于该情况.
为什么不关注呢?
请向我解释一个lambda表达式如何使用和修改其封闭类的实例变量,但只能使用其封闭范围的局部变量.(除非是最终的或有效的决赛?)
我的基本问题是,在范围的上下文中,类的实例变量如何在lambda中可修改而局部变量不可修改.
如何userId在我的匿名内部子类中获取传递给此方法的值?
public void doStuff(String userID) {
doOtherStuff(userID, new SuccessDelegate() {
@Override
public void onSuccess() {
Log.e(TAG, "Called delegate!!!! "+ userID);
}
});
}
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
不能在不同方法中定义的内部类中引用非最终变量userID
我很确定我不能将它指定为final,因为它是一个具有未知值的变量.我听说这种语法确实以某种方式保留了范围,所以我认为必须有一个我还不太了解的语法技巧.
class Outer{
private String x = "instance variable";
void doStuff(){
String z = "local variable";
class Inner{
public void seeOuter(){
System.out.println("Outer x is : "+ x);
System.out.println("Local variable z is : " + z); //won't compile
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将局部变量z标记为final可解决问题:
final String z = "local variable"; //Now inner object can use it.
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下发生了什么吗?
我确切地知道为什么在我尝试访问非最终局部变量的情况下它无法编译.
即使方法完成且局部变量超出范围,创建局部变量final也能保持活着吗?
最终的局部变量是否存储在堆而不是堆栈中?
如果此方法的变量'commonSet'是类级别字段,则以下代码是否会导致相同的问题.如果它是类级别字段,我将不得不在同步块中包装添加设置操作,因为HashSet不是线程安全的.我应该在下面的代码中做同样的事情,因为多个线程正在添加到集合,甚至当前线程可能会继续改变集合.
public void threadCreatorFunction(final String[] args) {
final Set<String> commonSet = new HashSet<String>();
final Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
commonSet.add(newValue());
}
}
};
new Thread(runnable, "T_A").start();
new Thread(runnable, "T_B").start();
}
Run Code Online (Sandbox Code Playgroud)
'commonSet'的引用是使用final锁定的.但是在其上运行的多个线程仍然可以破坏集合中的值(它可能包含重复项?).其次,混淆是因为'commonSet'是一个方法级变量 - 它的相同引用将在调用方法的堆栈内存(threadCreatorFunction)和运行方法的堆栈内存 - 这是正确的吗?
有很多与此相关的问题:
但是,我不能看到他们强调线程安全部分这种共享/传递可变性.
我首先问过这个关于final在Java 中使用匿名内部类的问题:
为什么我们使用带有匿名内部类的final关键字?
我实际上正在阅读马丁奥德斯基的Scala书.似乎Scala简化了很多Java代码,但对于Scala闭包,我注意到了一个显着的差异.
在Java中,我们使用匿名内部类"模拟"闭包,捕获最终变量(将被复制到堆上而不是堆栈中),在Scala中我们可以创建一个可以捕获val的闭包,但是也是一个var,因此在闭包调用中更新它!
所以我们可以使用没有final关键字的Java匿名内部类!我还没读完这本书,但是现在我没有找到关于这种语言设计选择的足够信息.
谁能告诉我,为什么马丁Odersky的,谁似乎真的照顾功能的副作用,选择关闭,以便能够同时捕捉val和var,而不是唯一的val?
Java和Scala实现的优点和缺点是什么?
谢谢
我有以下课程:
public class Item{
private String name;
//setter getter
}
Run Code Online (Sandbox Code Playgroud)
和物品的集合.我想得到Collection中最后一项的名字.要做到这一点,我只需迭代所有集合并使用最后.问题是我不知道为什么它迫使我使用一个元素String数组.
为什么我必须使用:
String[] lastName = {""};
items.forEach(item -> lastName[0] = item.getName());
System.out.println(lastname[0]);
Run Code Online (Sandbox Code Playgroud)
代替:
final String lastName;
items.forEach(item -> lastName = item.getName());
System.out.println(lastname);
Run Code Online (Sandbox Code Playgroud) 我是java新手并尝试一些访问方法,我遇到了一些我不理解的东西.下面的代码工作正常,打印9并没有给出任何编译错误.我认为这段代码应该给出编译错误,并且测试方法中的数字应该是不可访问的,因为新的Human()是一个完全不同的类的实例.谁能解释一下这里发生了什么?
public class Test{
public static void main(String[] args) {
int number = 9;
test("holla",new Human(){
@Override
void test() {
// TODO Auto-generated method stub
System.out.println(number); // I think this line should not compile
}
});
}
private static void test(String a ,Human h){
h.test();
}
}
Run Code Online (Sandbox Code Playgroud)
人类
public abstract class Human {
abstract void test();
}
Run Code Online (Sandbox Code Playgroud) 当我编写这段代码时,我得到一个编译时错误,上面写着: 'lambdas中的变量必须是最终的或有效的最终'.
现在,我得到这个从行中删除i:
futureLists.add(executorService.submit(() - >"Hello world"+ i));
解决了这个问题.
但我想知道为什么存在这样的要求?
根据JLS,它说的是:
使用但未在lambda表达式中声明的任何局部变量,形式参数或异常参数必须声明为final或有效final,否则在尝试使用时会发生编译时错误.
但它没有说明,为什么存在这样的要求.但是为什么Java工程师对lambdas强制执行这样的要求呢?
public class test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future<String>> futureLists = new ArrayList<>();
for (int i = 0; i < 20; i++) {
futureLists.add(executorService.submit( () -> "Hello world" + i));
}
for (Future<String> itr:futureLists) {
System.out.println(itr.get());
}
}
}
Run Code Online (Sandbox Code Playgroud) 方法 - 本地内部类不能访问局部变量,因为方法结束后方法本地内部类的实例可能仍然存在.但是一旦局部方法结束,局部变量就会消失.我了解到方法本地内部类可以访问最终的局部变量,这是否意味着在方法结束后最终的局部变量仍然存活?