- //只有定义成 final String obj 才不会报错
- public void test(final String obj)
- {
- Thread myThread = new Thread() {
- public void run() {
- System.out.println(obj);
- }
- };
- myThread.start();
- }
- public class OuterClass {
- public void outerDoSomething() {
- final String localObj = "hello";
- InnerClass innerObj = new class InnerClass {
- public void innerDoSomething() {
- // do with localObj
- }
- };
- }
- }
如果将一个访问了final的局部变量的内部类进行反编译,可以发现该变量是被作为构造函数的参数传入进去的,当然与之一起传入的参数还有外部类引用this。
实际经过编译,生成的字节码如下:
- public class OuterClass {
- public void outerDoSomething(){
- final String localObj = "hello";
- class InnerClass{
- private String obj;
- public InnerClass(String obj) {
- this.obj = obj;
- }
- public void innerDoSomething(){
- // do with obj
- }
- };
- InnerClass innerObj = new InnerClass(localObj);
- }
- }
荒唐原因:Java竟然允许内部类对象访问局部变量!
要知道局部变量的生命周期与局部内部类的对象的生命周期的不一致。局部变量当所处的函数执行结束后就已经死亡了,不存在了,但是局部内部类对象还可能一直存在(只要有人还引用该对象),这是就会出现了一个悲剧的结果,局部内部类对象访问一个已不存在的局部变量。
Java为了避免上述情况,才发明了上述机制,偷偷地将局部变量的引用放在内部类对象的成员变量中。
但是解决了生命周期的问题之后,又引出了另一个问题,因为局部变量和内部类中使用的变量是同一个对象呢?
比如下面的例子,而且如果不强制使用final,我们根本就不知道执行时,obj到底是哪个对象:
- public class helloWorld
- {
- public void test()
- {
- String obj = "hello"; // 不使用final
- Thread myThread = new Thread() {
- public void run() {
- System.out.println(obj); // ojb到底是哪个?
- }
- };
- myThread.start();
- }
-
- public static void main(String [] argv)
- {
- helloWorld hello = new helloWorld();
- hello.test();
- }
- }
又比如下面的例子,
- public class helloWorld
- {
- public void test()
- {
- String obj = "hello"; // 不使用final
- Thread myThread = new Thread() {
- public void run() {
- }
- };
- myThread.start();
- System.out.println(obj); // obj到底是什么?
- }
-
- public static void main(String [] argv)
- {
- helloWorld hello = new helloWorld();
- hello.test();
- }
- }