- 浏览: 190352 次
- 性别:
文章分类
最新评论
-
路人甲wxf:
.net可以在不使用证书的情况下修改密码,java做不到吗?
添加用户、修改ad密码 -
zxsosozhuzhu:
你好,我也遇到这个问题了,但是按照你的方法还是附件中文还是乱码 ...
java mail 纯文本附件乱码的解决方案 -
balaschen:
can4you 写道 请教问题:你好,请教一个问题,我现在要模 ...
spring2.0事务配置实验 -
can4you:
/**
* Created: 2007-2-1
* ...
FreeMarker解析字符串模板 -
can4you:
请教问题:你好,请教一个问题,我现在要模拟两个事务同时更新一 ...
spring2.0事务配置实验
先看这段代码:
一个很简单的例子,使用一个匿名类来处理button的事件,本来以已经习惯于匿名类只能引用上层的final变量,突然想到,当构造函数ShowAnonymousClass执行完毕之后,myTextArea这个local变量应该就失效了,当点击按钮的时候,为啥myTextArea变量对TextArea对象的应用依然有效?final 变量的具体语义究竟是什么,google一把,尽是final变量的值或引用不能改变之类的说法,查了java 语法规范也没找到,谁来说说,local变量,加了final究竟多了什么魔法?莫非类似于闭包?
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
感谢两位的讨论,现在差不多搞清了,对于不定义成final,如果在其他地方对变量进行赋值,这个变量的地址是变了,但匿名类里面的变量还是指向原先的地址(因为匿名类还引用它,所以不会被垃圾回收),和外层变量指向的地址不一致了,这样就产生了语意的不一致,而不是匿名类里面的地址就有可能是空的。
你这里的“语意”是指什么?
对, 这里不是为空, 而是不同的对象了。
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
感谢两位的讨论,现在差不多搞清了,对于不定义成final,如果在其他地方对变量进行赋值,这个变量的地址是变了,但匿名类里面的变量还是指向原先的地址(因为匿名类还引用它,所以不会被垃圾回收),和外层变量指向的地址不一致了,这样就产生了语意的不一致,而不是匿名类里面的地址就有可能是空的。
PS: 看不懂javap之后的东西。
没有搞过汇编语言的话直接看JVM指令可能有点费劲, 翻译成Java语法就是这样:
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
不矛盾, 拷贝的是到对象的引用, 而不是克隆复制对象.
这其实是编译器的特殊处理. 最简单的研究办法, 写这么一个类:
编译以后再 javap:
一切都清楚了.
要求必须加 final 应该是为了语义的一致性. 不然匿名类被构造好以后, 上层变量如果被重新赋值, 但匿名类从语义上引用外层变量, 值却还是它构造时候的, 逻辑上就错误了.
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
PS: 看不懂javap之后的东西。
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
不矛盾, 拷贝的是到对象的引用, 而不是克隆复制对象.
这其实是编译器的特殊处理. 最简单的研究办法, 写这么一个类:
编译以后再 javap:
一切都清楚了.
要求必须加 final 应该是为了语义的一致性. 不然匿名类被构造好以后, 上层变量如果被重新赋值, 但匿名类从语义上引用外层变量, 值却还是它构造时候的, 逻辑上就错误了.
public class ShowAnonymousClass extends JFrame { Button myButton; int count; public ShowAnonymousClass() { super("Inner Class Frame"); myButton = new Button("click me"); final TextArea myTextArea = new TextArea(); //就是这句 getContentPane().add(myButton, BorderLayout.CENTER); getContentPane().add(myTextArea, BorderLayout.NORTH); myButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ count++; myTextArea.setText("button clicked: " + count + " times"); } }); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { ShowAnonymousClass mainFrame = new ShowAnonymousClass(); mainFrame.setSize(300,300); mainFrame.setVisible(true); } }
一个很简单的例子,使用一个匿名类来处理button的事件,本来以已经习惯于匿名类只能引用上层的final变量,突然想到,当构造函数ShowAnonymousClass执行完毕之后,myTextArea这个local变量应该就失效了,当点击按钮的时候,为啥myTextArea变量对TextArea对象的应用依然有效?final 变量的具体语义究竟是什么,google一把,尽是final变量的值或引用不能改变之类的说法,查了java 语法规范也没找到,谁来说说,local变量,加了final究竟多了什么魔法?莫非类似于闭包?
评论
13 楼
balaschen
2007-01-12
语义,错别字:)
12 楼
dengyin2000
2007-01-12
balaschen 写道
引用
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
感谢两位的讨论,现在差不多搞清了,对于不定义成final,如果在其他地方对变量进行赋值,这个变量的地址是变了,但匿名类里面的变量还是指向原先的地址(因为匿名类还引用它,所以不会被垃圾回收),和外层变量指向的地址不一致了,这样就产生了语意的不一致,而不是匿名类里面的地址就有可能是空的。
你这里的“语意”是指什么?
对, 这里不是为空, 而是不同的对象了。
11 楼
balaschen
2007-01-12
引用
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
感谢两位的讨论,现在差不多搞清了,对于不定义成final,如果在其他地方对变量进行赋值,这个变量的地址是变了,但匿名类里面的变量还是指向原先的地址(因为匿名类还引用它,所以不会被垃圾回收),和外层变量指向的地址不一致了,这样就产生了语意的不一致,而不是匿名类里面的地址就有可能是空的。
10 楼
歆渊
2007-01-11
dengyin2000 写道
PS: 看不懂javap之后的东西。
没有搞过汇编语言的话直接看JVM指令可能有点费劲, 翻译成Java语法就是这样:
public class ShowAnony { public void test(final int n) { new ShowAnony$1(this, n).run(); } } final class ShowAnony$1 implements java.lang.Runnable { final int val$n; final ShowAnony this$0; ShowAnony$1(ShowAnony this$0, int n) { this.this$0 = this$0; this.val$n = n; } public void run() { this.val$n + 1; } }
9 楼
dengyin2000
2007-01-11
complystill 写道
balaschen 写道
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
不矛盾, 拷贝的是到对象的引用, 而不是克隆复制对象.
这其实是编译器的特殊处理. 最简单的研究办法, 写这么一个类:
public class ShowAnony { public void test(final int n) { new Runnable() { public void run() { int m = n+1; } }.run(); } }
编译以后再 javap:
D:\temp>javap -c ShowAnony$1 Compiled from "ShowAnony.java" final class ShowAnony$1 extends java.lang.Object implements java.lang.Runnable{ final int val$n; final ShowAnony this$0; ShowAnony$1(ShowAnony, int); Code: 0: aload_0 1: aload_1 2: putfield #1; //Field this$0:LShowAnony; 5: aload_0 6: iload_2 7: putfield #2; //Field val$n:I 10: aload_0 11: invokespecial #3; //Method java/lang/Object."<init>":()V 14: return public void run(); Code: 0: aload_0 1: getfield #2; //Field val$n:I 4: iconst_1 5: iadd 6: istore_1 7: return }
一切都清楚了.
要求必须加 final 应该是为了语义的一致性. 不然匿名类被构造好以后, 上层变量如果被重新赋值, 但匿名类从语义上引用外层变量, 值却还是它构造时候的, 逻辑上就错误了.
拷贝的是引用(也就是地址)。 如果不是定义成final,然后在其他地方对这个变量进行赋值的话, 这个变量的地址就变了。 那么这个匿名类里面的地址就有可能是空的。应该是这样理解吧。
PS: 看不懂javap之后的东西。
8 楼
歆渊
2007-01-11
balaschen 写道
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
不矛盾, 拷贝的是到对象的引用, 而不是克隆复制对象.
这其实是编译器的特殊处理. 最简单的研究办法, 写这么一个类:
public class ShowAnony { public void test(final int n) { new Runnable() { public void run() { int m = n+1; } }.run(); } }
编译以后再 javap:
D:\temp>javap -c ShowAnony$1 Compiled from "ShowAnony.java" final class ShowAnony$1 extends java.lang.Object implements java.lang.Runnable{ final int val$n; final ShowAnony this$0; ShowAnony$1(ShowAnony, int); Code: 0: aload_0 1: aload_1 2: putfield #1; //Field this$0:LShowAnony; 5: aload_0 6: iload_2 7: putfield #2; //Field val$n:I 10: aload_0 11: invokespecial #3; //Method java/lang/Object."<init>":()V 14: return public void run(); Code: 0: aload_0 1: getfield #2; //Field val$n:I 4: iconst_1 5: iadd 6: istore_1 7: return }
一切都清楚了.
要求必须加 final 应该是为了语义的一致性. 不然匿名类被构造好以后, 上层变量如果被重新赋值, 但匿名类从语义上引用外层变量, 值却还是它构造时候的, 逻辑上就错误了.
7 楼
balaschen
2006-12-26
今天又做了个实验,发现当local变量被innerClass引用的时候,在innerClass的生命周期没结束前,是不会被垃圾回收的:
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
public class ShowAnonymousClass extends JFrame { private TextArea myTextArea; public ShowAnonymousClass() { super("Inner Class Frame"); Button button1 = new Button("button1"); myTextArea = new TextArea(); getContentPane().add(button1, BorderLayout.WEST); getContentPane().add(myTextArea, BorderLayout.NORTH); final CountValue count = new CountValue(0); button1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ count.incValue(); myTextArea.setText(myTextArea.getText()+"\nbutton1 clicked: " + count.getCount() + " times"); } }); Button button2 = new Button("button2"); getContentPane().add(button2, BorderLayout.EAST); button2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ count.incValue(); myTextArea.setText(myTextArea.getText()+"\nbutton2 clicked: " + count.getCount() + " times"); } }); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { ShowAnonymousClass mainFrame = new ShowAnonymousClass(); mainFrame.setSize(300,300); mainFrame.setVisible(true); } public class CountValue{ private int count; public CountValue(int count){ this.count = count; } public int getCount(){ return this.count; } public void incValue(){ this.count ++; } } }
运行这段代码可以发现,在其中一个innerClass内修改CountValue的值,会影响另外一个innerClass引用的CountValue,很显然,这两个innerClass的CountValue引用,指向同一个对象,这和拷贝上层的local变量引用的对象到innerClass内部,显然是矛盾的,还是搞不清楚Java的local变量的作用域问题
6 楼
balaschen
2006-12-25
怎么没人讨论,都跑去过生蛋节了?
5 楼
balaschen
2006-12-21
http://forum.java.sun.com/thread.jspa?threadID=736802&messageID=4232040
这个帖子说法和我上面提到的类似,有没有权威的文档来证明这种说法呢?
这个帖子说法和我上面提到的类似,有没有权威的文档来证明这种说法呢?
4 楼
balaschen
2006-12-21
在一个台湾人的论坛上看到,解释的还比较合理:
http://www.javaworld.com.tw/jute/post/view?bid=29&id=66043&sty=3&age=0&tpg=1&ppg=1
大致的意思是说,innerClass对于访问的上层local变量,因为local变量的生命周期的原因,是无法直接访问的,因此,会把local变量拷贝一个副本到innerClass内作为一个field保存起来,这样一来,innerClass内部使用的那个local变量,和外层的并不是同个变量,在innerClass内部修改innerClass引用local变量的值(假设允许修改的话),并不会影响外层的local变量的值,这样就很容易引起混淆,因此,对innerClass引用的local变量加上final修饰符,限制这些变量的值不能改变,这样一来,语义就统一了,这也可以理解为什么innerClass可以直接引用外层类的变量,因为innerClass可以透过其持有的上层类实例的引用来访问其成员变量。
如果这种说法正确的话,final 变量并没有额外的语义,而是innerClass有点类似于动态语言的闭包,从这点上看,似乎没有必要把innerClass引用的上层local变量规定为必须final,不final不是更灵活么?
http://www.javaworld.com.tw/jute/post/view?bid=29&id=66043&sty=3&age=0&tpg=1&ppg=1
大致的意思是说,innerClass对于访问的上层local变量,因为local变量的生命周期的原因,是无法直接访问的,因此,会把local变量拷贝一个副本到innerClass内作为一个field保存起来,这样一来,innerClass内部使用的那个local变量,和外层的并不是同个变量,在innerClass内部修改innerClass引用local变量的值(假设允许修改的话),并不会影响外层的local变量的值,这样就很容易引起混淆,因此,对innerClass引用的local变量加上final修饰符,限制这些变量的值不能改变,这样一来,语义就统一了,这也可以理解为什么innerClass可以直接引用外层类的变量,因为innerClass可以透过其持有的上层类实例的引用来访问其成员变量。
public class ShowAnonymousClass extends JFrame { Button myButton; private TextArea myTextArea; //把myTextArea定义为成员变量 int count; public ShowAnonymousClass() { super("Inner Class Frame"); myButton = new Button("click me"); myTextArea = new TextArea(); //去掉final getContentPane().add(myButton, BorderLayout.CENTER); getContentPane().add(myTextArea, BorderLayout.NORTH); myButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ count++; myTextArea.setText("button clicked: " + count + " times"); } }); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { ShowAnonymousClass mainFrame = new ShowAnonymousClass(); mainFrame.setSize(300,300); mainFrame.setVisible(true); } }
如果这种说法正确的话,final 变量并没有额外的语义,而是innerClass有点类似于动态语言的闭包,从这点上看,似乎没有必要把innerClass引用的上层local变量规定为必须final,不final不是更灵活么?
3 楼
balaschen
2006-12-21
如果final的local变量没有特殊的语义,innerClass似乎也没必要要求上层的local变量必须final吧,继续google
2 楼
balaschen
2006-12-21
myTextArea指向的对象当然是存在的,但myTextArea作为local变量,构造函数执行完毕,本身应该实效,被垃圾回收。变量失效和变量指向的对象失效,是两回事吧。
1 楼
sorphi
2006-12-21
>>当构造函数ShowAnonymousClass执行完毕之后,myTextArea这个local变量应该就失效了
getContentPane().add(myTextArea, BorderLayout.NORTH);
myTextArea指向的对象被其他的对象(contentPane)钩住了
getContentPane().add(myTextArea, BorderLayout.NORTH);
myTextArea指向的对象被其他的对象(contentPane)钩住了
发表评论
-
利用sax和xslt转换csv文件内容
2008-02-03 15:57 3195package jaxp; import java.io.B ... -
通过BOM探测文本文件编码类型
2008-01-24 15:19 2394从tomcat源码抄来的改的: private Object ... -
java mail 纯文本附件乱码的解决方案
2008-01-24 15:16 6128java mail在发送纯文本附件时,当附件内容的编码和jvm ... -
ntdsutil设置AD查询返回最大条目
2008-01-18 16:56 1732AD缺省的最大查询结果为1000个,如果超过1千个,则需要客户 ... -
struts2-layout
2007-11-09 18:17 51testvvvv -
Http基本明文验证
2007-06-13 12:55 1856base64解码使用了novell的实现 java 代码 ... -
如何启用活动目录SSL连接
2007-06-13 10:49 3430ad:http://www.cnblogs.com/chnki ... -
AD User重要属性
2007-06-11 14:55 2188objectClass=User User-Account ... -
添加用户、修改ad密码
2007-06-11 11:28 15842java 代码 /** * ... -
ldap 访问AD测试
2007-06-08 16:37 4404java 代码 java 代码 /** ... -
JNDI 连接Windows Active Directory 教程(转)
2007-06-08 16:36 3280个人收藏,来源:http:// ... -
正确认识memcached的缓存失效
2007-05-29 10:56 9630最近javaeye上memcached相当火,不少人把它当作s ... -
webwork结合memcached实现sna架构
2007-05-28 14:04 5795实现思路,使用一个拦截器实现session的处理: ... -
activemq实验
2007-05-17 11:37 2129实验环境:activemq4.1.1/spring1.2.8 ... -
发现用Spring配置事务不爽的一个地方
2007-05-11 16:41 2039举个例子: SomeService implement I ... -
Java Transaction Design Strategies读书笔记
2007-05-14 15:34 2423第一种:Client Owner Transaction Ma ... -
有谁知道银行的跨行转帐是怎么保证交易的原子性和一致性?
2007-05-10 09:18 23045最近在看《Java Transaction Design St ...
相关推荐
1.Nested Class(嵌套类) 1.1.Nested class 1.2.Nested class的分类 1.3.Nested class的使用原因 2.Static Nested Classes 2.1.static nested class访问enclosing ...3.3.Local Inner Class(Inner Class)
Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)
java易混淆的地方,final, finally, finalize的区别,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类
java-内部类(InnerClass)详解.pdf
this a java instance about innerclass application
InnerClass01Test.java
局部内部类 Local inner 马克-to-win java视频的详细介绍
第11章 内部类(Inner class).ppt第11章 内部类(Inner class).ppt
匿名内部类 inner class 马克-to-win java视频的详细介绍
Java中inner_class内部类
Java内部类(innerclass).docx
匿名内部类 inner class 马克-to-win java视频的详细介绍
java程序代码,供大家参考。不会的时候可以看看啊
Instance inner 实例内部类 马克-to-win java视频的介绍
很好的Java面试题第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
Java 面试题 经典 第一,谈谈final, finally, finalize的区别。...第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。 第四,&和&&的区别。 第五,HashMap和Hashtable的区别。
本节内容包括 接口基本概念 使用接口的例子 接口的定义 接口的实现 接口与抽象类 接口和回调 内部类(介绍)
内部类的定义和普通类的定义没什么区别,它可以直接访问和引用它的外部类的所有变量和方法(包括private),就像外部类中的其他非static成员的功能一样。区别是,外部类只能声明为public和default,而内部类可以声明...
Instance inner 实例内部类 马克-to-win java视频的介绍
Instance inner 实例内部类 马克-to-win java视频的介绍