java 漏洞? 关于final 和 method anonymous class

cozmic 2005-08-05 01:09:50
[问题]
呵呵,不知道为什么,在方法中的匿名内部类里就是可以
访问外部类的非 final 变量,并且改变其值.
这其中有什么奥妙么?

[分析]
让我们看看代码,代码中注意 times 并不是final类型,
但是在方法toStart中的匿名内部类引用并修改了他的值。
代码功能:间隔2秒输出一个累次减小的数字,待到
数字减为0,程序退出。
- — — — — — — — — — — — — — — — — — — — — — — —
import java.util.Timer;
import java.util.TimerTask;

public class CounterTimer {
//减少次数
private int times;
private Timer timer;
public CounterTimer(int times) {
this.times = times;
timer = new Timer();
}

public void toStart() {
//匿名内部类
timer.schedule(new TimerTask(){
public void run() {
if(times > 0)
System.out.println(times — );
else
toStop();
}

},0,2000);
}

public void toStop() {
timer.cancel();
}

public static void main(String args[]){
CounterTimer ct = new CounterTimer(5);
ct.toStart();
}

}

- — — — — — — — — — — — — — — — — — — —
请再看一例:
定义了方法huhu()

- — — — — — — — — — — — — — — — — — — —
public class TestFinal {
//注意不是static final int var
static int var = 10;
public static void huhu() {
(new A() {
public void toPrint() {
System.out.println( Integer.toString(++var));

}
}).toPrint();
}

public static void main(String[] args) {
huhu();
}

}

class A {
public void toPrint() {
}

}
- — — — — — — — — — — — — — — — — —
输出结果:11
- — — — — — — — — — — — — — — — — —
[结论]
呵呵,写到这里 可以有个小结了:
在外部类的方法中创建的匿名内部类,可以引用
外部类的非final 变量,并修改:)

[验证]
莫非真的是可以么? 我又这样测试了一下:
注意在TestFinal2中,把huhu()的代码移到了
main()方法内。
- — — — — — — — — — — — — — — — — — –
public class TestFinal2 {
public static void main(String[] args) {
int var = 10;
//匿名内部类
(new A() {
public void toPrint() {
System.out.println(++var); //报错~~
}

}).toPrint();

}
}

class A {
public void toPrint(int var) {
}

}
- — — — — — — — — — — — — — — — — — — — — –
...全文
290 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
cozmic 2005-08-06
  • 打赏
  • 举报
回复
具体问题 请访问
http://blog.javaresearch.org/page/cozmic
的Kaleidoscope 类别中的文章
cozmic 2005-08-06
  • 打赏
  • 举报
回复
我在验证码中 想说明:如果这个匿名内部类不在外部类的非main()方法中,
那么则是不允许访问变量外部类的非fianl 变量var。请 homesos运行下我的
验证码,一定会报错的!~
cozmic 2005-08-06
  • 打赏
  • 举报
回复
To: homesos
您没有理解我的问题~~ ,请看一下代码:
------------
[代码分析]
让我们看看代码,代码中注意外部类CounterTimer 中的非final类型 int times,
可以在CounterTimer类的方法 toStart()中的匿名内部类中访问的到,直接引用并改变其值.

代码功能:间隔2秒输出一个累次减小的数字,待到数字减为0,程序退出。

import java.util.Timer;
import java.util.TimerTask;

public class CounterTimer {
//减少次数
private int times;
private Timer timer;
public CounterTimer(int times) {
this.times = times;
timer = new Timer();
}

public void toStart() {
//匿名内部类
timer.schedule(new TimerTask(){
public void run() {
if(times > 0)
System.out.println(times — );
else
toStop();
}

},0,2000);
}

public void toStop() {
timer.cancel();
}

public static void main(String args[]){
CounterTimer ct = new CounterTimer(5);
ct.toStart();
}

}
-----------------
确实是 toStart()中的匿名内部类 可以访问外部类的非final 变量 times !
homesos 2005-08-05
  • 打赏
  • 举报
回复
在你的验证代码中,称{把huhu()的代码移到了main()方法内。}

事实真的如此吗?

请阁下再检查一下变量 var 的差异。
homesos 2005-08-05
  • 打赏
  • 举报
回复
楼上兄弟: interhanchi(路曼曼其修远兮,吾将上下而求索.)
已经说的很清楚了,再仔细看看先
homesos 2005-08-05
  • 打赏
  • 举报
回复
既知 闻道有先后
又不arbitrary

那还
--java 漏洞?

用这么专业的词汇,俺们可真是不得不服呀
我以为,天才又降生了呢!!!
cozmic 2005-08-05
  • 打赏
  • 举报
回复
没有人知道了么?
cozmic 2005-08-05
  • 打赏
  • 举报
回复
TO: interhanchi
您给的帖子 好像没有提到我遇到的问题
cozmic 2005-08-05
  • 打赏
  • 举报
回复
To: homosos
闻道有先后嘛~
有什么异议可以拿到桌面上说,
何必那么arbitrary
homesos 2005-08-05
  • 打赏
  • 举报
回复
还是老老实实看书学习吧
interhanchi 2005-08-05
  • 打赏
  • 举报
回复
哈哈,看不了,我帮你帖出来1

To cbu(阿牛) 兄:
昨天第一个问题回答的不好(错误),今天看了一下书,特地补充一下,不足之处,请指正。
匿名内部类使用在它外部定义的一个对象,并不是为了防止继承,而是由于匿名内部类没有构建器,它只能通过匿名内部类中对象的实例初始化进行构建。而对象的实例初始化应该是在编译期确定的,这样他们实例初始化的时候不能接收一个外部的在运行期才确定的数据,所以只能接收一个final类型的数据,因为final数据是一个编译期就确定下来的对象。

To cbu(阿牛): 我总算你弄明白了匿名内部类为什么只能用final.是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final。因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。你看看下面的例子:
public class Outer{
private int m = (int)(Math.random()*100);
public static void main(String args[]){
Outer that = new Outer();
that.go((int)(Math.random()*100),(int)(Math.random()*100));
}
public void go(int x,final int y){
int a = x+y;
final int b = x-y;
class Inner{
public void method(){
System.out.println("m is " + m);
// System.out.println("x is " + x);//非法
System.out.println("y is " + y);
// System.out.println("a is " + a);//非法
System.out.println("b is " + b);
}
}
Inner that = new Inner();
that.method();
}
}

这条规则的翻译有问题,我想该是《java变成死相》的翻译出了问题
如果一个匿名内部类出现在一个方法的内部,那么它如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final

^_^,其实很多细节我也不是很懂,所以准备看完thinking in java后,看那本 深入java虚拟机.这样才能知其然知其所以然!
homesos 2005-08-05
  • 打赏
  • 举报
回复
楼主可真强

看看自己的代码先……
cozmic 2005-08-05
  • 打赏
  • 举报
回复
to: interhanchi
看不了啊~~ 网页报错~
可不可以贴出来,或者发送我的信箱:cozmic@163.com
interhanchi 2005-08-05
  • 打赏
  • 举报
回复
^_^ ,给你个帖子,看一下吧!

http://61.186.252.131/Expert/topic/1184/1184188.xml?temp=.2330286
cozmic 2005-08-05
  • 打赏
  • 举报
回复
呵呵,可否解释下?

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧