我想我已经在JavaScript中遇到了这种经典情况.
通常程序员会希望下面的代码可以打印"Peter","Paul","Mary".
但事实并非如此.谁能解释为什么它在Java中以这种方式工作?
这个Java 8代码编译好并打印3次"Mary".
我想这是一个问题,它是如何在内心深处实施的,
但是......这不是表明底层实施的错误吗?
import java.util.List;
import java.util.ArrayList;
public class Test008 {
public static void main(String[] args) {
String[] names = { "Peter", "Paul", "Mary" };
List<Runnable> runners = new ArrayList<>();
int[] ind = {0};
for (int i = 0; i < names.length; i++){
ind[0] = i;
runners.add(() -> System.out.println(names[ind[0]]));
}
for (int k=0; k<runners.size(); k++){
runners.get(k).run();
}
}
}
Run Code Online (Sandbox Code Playgroud)
相反,如果我使用增强的for循环(同时添加Runnables),则捕获正确的(即所有不同的)值.
for (String name : names){
runners.add(() -> System.out.println(name));
}
Run Code Online (Sandbox Code Playgroud)
最后,如果我使用经典的for循环(同时添加Runnables),那么我会得到一个编译错误(这很有意义,因为变量i不是最终的或有效的最终).
for (int i = …Run Code Online (Sandbox Code Playgroud) 我不明白为什么我不能总是从'listener'或'handler'中访问变量.
这是我的代码:
Button btnDownload = new Button(myparent, SWT.NONE);
btnDownload.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
btnDownload.setEnabled(false); // I CAN'T
}
});
Run Code Online (Sandbox Code Playgroud)
唯一的方法是使用final关键字声明它:
final Button btnDownload = new Button(myparent, SWT.NONE);
Run Code Online (Sandbox Code Playgroud)
为什么我需要声明变量final以获取事件内的访问权限?
在下面的代码中,为什么我不能从另一个线程中看到变量"i"?
public class Main {
public static void main(String[] args) {
int i = 0;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(i);
}
}).start();
}
}
Run Code Online (Sandbox Code Playgroud)
为什么我可以在下面的代码中看到它?
public class Main {
int i = 0;
public static void main(String[] args) {
new Main().method();
}
private void method() {
new Thread(new Runnable() {
@Override
public void run() {
i = 1;
}
}).start();
}
}
Run Code Online (Sandbox Code Playgroud) 在通过构造函数传递给匿名类的最终变量中,Jon Skeet提到变量通过自动生成的构造函数传递给匿名类实例.在这种情况下,为什么我无法使用反射来查看构造函数:
public static void main(String... args) throws InterruptedException {
final int x = 100;
new Thread() {
public void run() {
System.out.println(x);
for (Constructor<?> cons : this.getClass()
.getDeclaredConstructors()) {
StringBuilder str = new StringBuilder();
str.append("constructor : ").append(cons.getName())
.append("(");
for (Class<?> param : cons.getParameterTypes()) {
str.append(param.getSimpleName()).append(", ");
}
if (str.charAt(str.length() - 1) == ' ') {
str.replace(str.length() - 2, str.length(), ")");
} else
str.append(')');
System.out.println(str);
}
}
}.start();
Thread.sleep(2000);
Run Code Online (Sandbox Code Playgroud)
}
输出是:
100
constructor : A$1()
Run Code Online (Sandbox Code Playgroud) 我正在阅读java中的匿名类,它说你可以访问封闭类的方法,但不能访问局部变量.为什么会这样?我在说这个:
编辑:旧的例子是错误的不反映我的意思.这应该是一个更好的例子,根据它在"访问封闭类的成员"部分http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html中所写的内容.
public class MyClass {
public interface SomeInterface{
public void someOtherMethod();
}
public void someMethod(int someLocalVar) {
SomeInterface myClass = new SomeInterface(){
public void someOtherMethod(){
someLocalVar = 0; // This must be final to work
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么这个限制解决有什么问题呢?
请考虑以下代码:
enum E {
A { public int get() { return i; } },
B { public int get() { return this.i; } },
C { public int get() { return super.i; } },
D { public int get() { return D.i; } };
private int i = 0;
E() { this.i = 1; }
public abstract int get();
}
Run Code Online (Sandbox Code Playgroud)
我在前2个枚举常量声明(A和B)上得到编译时错误,但最后2个编译正常(C&D).错误是:
A行的错误1:非静态变量i无法从静态上下文引用
B行上的错误2:我在E中有私有访问权限
由于get是一个实例方法,我不明白为什么我不能i以我想要的方式访问实例变量.
注意:private从声明中删除关键字i也会使代码可编辑,我也不明白.
使用Oracle JDK 7u9.
编辑
正如评论中所指出的,这不是枚举特有的,下面的代码会产生相同的行为:
class E …Run Code Online (Sandbox Code Playgroud) 我想将一个字符串传递给asynctask.谁能告诉我它是如何完成的?我的getEntity需要方法getEntity(Activity,String,EntityGetListener)但我继续传递这个String []
String pass= story.get(position).getEntity();
new RemoteDataTask().execute(pass);
private class RemoteDataTask extends AsyncTask<String, String, Long> {
@Override
protected Long doInBackground(String... params) {
// TODO Auto-generated method stub
EntityUtils.getEntity(activity, params, new EntityGetListener() {
@Override
public void onGet(Entity entity) {
viewcount = entity.getEntityStats().getViews();
}
@Override
public void onError(SocializeException error) {
}
});
return null;
}
}
Run Code Online (Sandbox Code Playgroud) Local Classes的Java文档说:
此外,本地类可以访问局部变量.但是,本地类只能访问声明为final的局部变量.当本地类访问封闭块的局部变量或参数时,它会捕获该变量或参数.例如,PhoneNumber构造函数可以访问局部变量numberLength,因为它被声明为final; numberLength是捕获的变量.
什么是捕获变量,它的用途是什么以及为什么需要它?请帮助我理解它的概念.
我有以下代码,它有点抽象我在Java程序中的实际实现:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = bufferedReader.readLine()) != null) {
String lineReference = line;
runLater(() -> consumeString(lineReference));
}
Run Code Online (Sandbox Code Playgroud)
这里我需要使用lambda表达式的引用副本,当我尝试使用时line我得到:
从lambda表达式引用的局部变量必须是最终的或有效的final
对我来说这似乎很尴尬,因为我所做的就是获取对象的新引用,这是编译器也可以自己解决的问题.
所以,我要说line是有效决赛在这里,因为它只是变得回路中的分配和其他地方.
任何人都可以对此有所了解并解释为什么这里需要它以及为什么编译无法解决它?
我们知道只能在匿名类中访问最终的局部变量,这里有一个很好的理由:为什么在匿名类中只能访问最终变量?.
但是,我发现如果变量是封闭类的成员字段,匿名类仍然可以访问非final变量:如何从匿名类内部访问封闭的类实例变量?
我很迷惑.我们确保只能在匿名类中访问最终的局部变量,因为我们不希望变量在匿名类和本地函数之间不同步.如果我们尝试访问匿名类中的非最终封闭类成员,则同样的理由应该适用于该情况.
为什么不关注呢?