关于匿名课和最终字段的解释我仍然不满意.有很多问题试图解释明显的问题,但我没有找到所有问题的答案:-)
假设以下代码:
public void method(final int i, int j) {
final int z = 6;
final int x = j;
int k = 5;
new Runnable() {
public void run() {
System.out.print(i);
System.out.print(x);
System.out.print(z);
System.out.print(k);
}
};
}
Run Code Online (Sandbox Code Playgroud)
k属性,无法编译此代码.z在编译期间用声明的值替换属性.当我搜索解决方案时,究竟是如何工作的i,x我发现这个答案说:
然后,编译器可以将匿名类中的lastPrice和price的使用替换为常量的值(在编译时,当然),并且您将不再有访问不存在的变量的问题
它如何适用于字段i,x如果它们是方法的参数?在编译期间不知道它们?这种方法可以发挥作用z.
另一方面,有关于堆栈问题的解释:
这允许Java编译器在运行时"捕获"变量的值,并将副本存储为内部类中的字段.一旦外部方法终止并且其堆栈框架已被移除,原始变量就会消失,但内部类的私有副本仍然存在于类的自身内存中
我会理解匿名类在创建过程中以某种方式复制了所有必需的内容(字段).缺失final有明显的问题,如果匿名类声明下面的某些代码会改变值,则执行使用可能的stale值.
但是,这可以解决当匿名类'方法在使用的属性范围之外执行时的问题.
但这种方法即使没有final声明也应该有效,因为它只是复制所有字段.
这两种方法对我来说都是独立的.说到哪 - 它可以解决我的问题 - …
可能重复:
不能引用在不同方法中定义的内部类中的非final变量
为什么内部类需要"final"外部实例变量[Java]?
class MyOuter {
private String x = "Outer";
void doStuff(){
final String z = "local variable";
class MyInner {
public void seeOuter(){
System.out.println("Outer x is" + x);
System.out.println("Local variable z is" + z); // does
// not compile if final keyword from String z is removed
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码工作正常.我想知道如果从String z中删除final关键字,编译器为什么会出错.最终的关键字制作有什么区别?
为什么SWING总是强迫我将某些特定物体标记为最终?因为这有时会使事情变得有点困难,有没有办法避免这种情况?
(INCOMPLETE EXAMPLE)它强制我将IExchangeSource变量标记为final:
public class MainFrame {
private final JTextArea textArea = new JTextArea();
public static void main(final IExchangeSource s) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new MainFrame(s);
}
});
}
public MainFrame(final IExchangeSource s) {
//build gui
s.update();
Run Code Online (Sandbox Code Playgroud) 如果我有这个匿名方法,我应该声明x变量为final.
private void testMethod (ListField<BeanModel> listField){
final ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>();
listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() {
@Override
public void handleEvent(ListViewEvent<BeanModel> be) {
loader.load();
}
});
}
Run Code Online (Sandbox Code Playgroud)
但是,如果loader是一个类字段,则没有必要将其声明为final:
public class testClass{
private ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>();
private void testMethod (ListField<BeanModel> listField){
listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() {
@Override
public void handleEvent(ListViewEvent<BeanModel> be) {
loader.load();
}
});
//Could I modify loader's reference here, before the method executes?
//loader = null;
}
}
Run Code Online (Sandbox Code Playgroud)
有没有人知道为什么他们保证局部变量在被访问时不会改变但是没有为类字段做?
我对函数式语言和闭包很满意,并对以下错误感到惊讶:"不能引用封闭范围中定义的非最终局部变量邀请".
这是我的代码:
Session dbSession = HibernateUtil.getSessionFactory().openSession();
Transaction dbTransaction = dbSession.beginTransaction();
Criteria criteria = dbSession.createCriteria(Invite.class).add(Restrictions.eq("uuid", path).ignoreCase());
Invite invite = (Invite) criteria.uniqueResult();
if (invite.isExpired()) {
// Notify user the invite has expired.
} else {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// ERROR: `invite` is not guaranteed to exist when this code runs
invite.setExpired(true);
}
}, MAX_TIME);
}
Run Code Online (Sandbox Code Playgroud)
据我了解,invite在TimeTask实例中引用是一个错误,因为不保证该变量存在.所以我的问题是,表达我想要的Java的方式是什么,即加载一个邀请,然后设置一个计时器,在一段时间后使邀请过期.
在Java中,我有以下代码
List<Integer> myList = new ArrayList<>();
for (int i=0;i<9;i++) {
myList.add(i);
}
Integer sum = 0;
myList.forEach(i -> {
sum = sum + i; // does not compile, sum needs to be final or effectively final
});
for(int i : myList) {
sum = sum + i; //runs without problems
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么我不能在lambda中改变sum的值?它与下面的for循环完全相同,或者我错了?有趣的是,如果我将main方法之外的整数和声明为静态,它也可以.谁能解释我为什么?
编辑:在另一个类似的问题Java 8支持闭包,答案似乎是:
它是向后兼容性和项目资源约束的组合.
但是,我仍然无法理解为什么它可以工作,如果我将数组和数组或我在main之外声明它.我还想了解下面的myList.forEach和for循环之间有什么区别,为什么一个有效,另一个没有.
我正在编写一个Android应用程序,其中我有几个按钮布局在网格中.我想设置每个按钮的onClick方法,所以我写了这个:
for (int i = 0; i < button.length; i++) {
for (int j = 0; j < button[0].length; j++) {
button[i][j].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
press(i, j);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
在press(int i, int j)别处实施的地方.我得到错误,"不能引用在不同方法中定义的内部类中的非最终变量i".
所以,现在我只需写出每个函数,如下所示:
button[0][0].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
press(0, 0);
}
});
button[0][1].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
press(0, 1);
}
});
// more like this...
Run Code Online (Sandbox Code Playgroud)
这有效,但看起来很傻.有没有更好的办法?
我从小就知道这final是一个关键字,当应用于变量时,不能将变量重新分配给其他东西."如果一个变量是最终的那么它就是一个常数"总结了许多,虽然我不是那个定义的粉丝,但它可能是一个很好的方法来记住这个概念.我只想说you cannot change the value of the variable(无论"价值"意味着什么).
我的生活很幸福,但有一天我深入了解method local inner classes......
方法内定义的内部类不能访问方法本身定义的变量.为什么?因为当类存在于Heap中并且它可能在方法完成后保持存在(类的有效引用可能被传递并存储在其他地方),这些变量存在于堆栈中并且在方法返回时它们会死亡.我们不希望内部类在以后尝试访问不再存在的变量,因为那时世界将会结束.
完善.这说得通.优秀!然后:除非你声明那些变量最终.....然后你的类可以访问它们,编译器不会把你送到地狱......
WHY???我的意思是,这是什么样的巫术?最终究竟做了什么以及为什么我不得不等待谈论方法本地内部类来解决这个问题?假设最终变量存储在堆中,无论它们在何处定义,除了使方法本地内部类快乐的概念之外,还有其他任何应用吗?
我尝试动态创建一个ImageView,我想将此imageView作为参数传递给侦听器中的方法.
ImageView imageView1 = new ImageView(LookActivity.this);
imageView1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
detectLocationAndShowPopUp(imageView1);
return true;
}
})
Run Code Online (Sandbox Code Playgroud)
但我正在采取以下错误:
不能在不同方法中定义的内部类中引用非最终变量imageView1.
我不想将imageView声明为final.我怎样才能克服这个问题?
我有一个listview,它使用自定义listAdapter进行设置.每个listView项中都有一个按钮来更改同一行中的textView.我该怎么做?以下是代码的一部分:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final int _position = position;
if (convertView == null) {
convertView = l_Inflater.inflate(R.layout.activity_today_sales_list_view, null);
holder = new ViewHolder();
holder.txt_itemName = (TextView) convertView.findViewById(R.id.itemNameTB);
holder.txt_itemPrice = (TextView) convertView.findViewById(R.id.priceTB);
holder.txt_plusBtn = (Button) convertView.findViewById(R.id.addBtn);
holder.txt_minusBtn = (Button) convertView.findViewById(R.id.minusBtn);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txt_plusBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Plus Btn", "Clicked");
}
});
holder.txt_minusBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Log.d("Minus …Run Code Online (Sandbox Code Playgroud)