- 浏览: 192199 次
- 性别:
文章分类
最新评论
-
路人甲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 3229package jaxp; import java.io.B ... -
通过BOM探测文本文件编码类型
2008-01-24 15:19 2432从tomcat源码抄来的改的: private Object ... -
java mail 纯文本附件乱码的解决方案
2008-01-24 15:16 6219java mail在发送纯文本附件时,当附件内容的编码和jvm ... -
ntdsutil设置AD查询返回最大条目
2008-01-18 16:56 1782AD缺省的最大查询结果为1000个,如果超过1千个,则需要客户 ... -
struts2-layout
2007-11-09 18:17 51testvvvv -
Http基本明文验证
2007-06-13 12:55 1886base64解码使用了novell的实现 java 代码 ... -
如何启用活动目录SSL连接
2007-06-13 10:49 3469ad:http://www.cnblogs.com/chnki ... -
AD User重要属性
2007-06-11 14:55 2234objectClass=User User-Account ... -
添加用户、修改ad密码
2007-06-11 11:28 15886java 代码 /** * ... -
ldap 访问AD测试
2007-06-08 16:37 4440java 代码 java 代码 /** ... -
JNDI 连接Windows Active Directory 教程(转)
2007-06-08 16:36 3307个人收藏,来源:http:// ... -
正确认识memcached的缓存失效
2007-05-29 10:56 9657最近javaeye上memcached相当火,不少人把它当作s ... -
webwork结合memcached实现sna架构
2007-05-28 14:04 5839实现思路,使用一个拦截器实现session的处理: ... -
activemq实验
2007-05-17 11:37 2178实验环境:activemq4.1.1/spring1.2.8 ... -
发现用Spring配置事务不爽的一个地方
2007-05-11 16:41 2074举个例子: SomeService implement I ... -
Java Transaction Design Strategies读书笔记
2007-05-14 15:34 2452第一种:Client Owner Transaction Ma ... -
有谁知道银行的跨行转帐是怎么保证交易的原子性和一致性?
2007-05-10 09:18 23292最近在看《Java Transaction Design St ...
相关推荐
Java编程语言中存在一些易混淆的概念,今天我们将探讨 Anonymous Inner Class、final、finally、finalize 的区别,Static Nested Class 和 Inner Class 的不同,&和&&的区别,HashMap 和 Hashtable 的区别,...
内部类分为几种类型,包括静态成员类(Static member class)、局部内部类(Local inner class)、匿名内部类(Anonymous inner class)以及嵌套接口(Nested interface)。在本讨论中,我们将主要聚焦于静态成员类...
Java 内部类(Inner Class)是 Java 语言的一个特性,它允许我们在一个类的内部定义另一个类。这种设计模式提供了更高的代码封装性和复用性,同时也为解决某些特定问题提供了方便。在“java_innerclass_instance.rar...
Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)
在Java编程语言中,局部内部类(Local Inner Class)是一种特殊的内部类形式,它被定义在某个方法或构造器的内部。与成员内部类不同,局部内部类只能在其定义的方法或构造器内被使用。本文主要探讨的是局部内部类...
2. 局部内部类:定义在方法内部的类,其作用域仅限于该方法,因此它不能访问方法外部的局部变量,除非这些变量是final的。 3. 匿名内部类:没有名字的内部类,通常用于快速实现接口或抽象类的一个简单版本,常用于...
在引用类型变量中,final 关键字可以用于限制变量的指向对象的地址不能被改变,但不影响对象内部的成员变量值的修改。例如: ```java public class FinalDemo2 { public static void main(String[] args) { final...
被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。 finally是一个异常处理时提供的finally块来执行任何清除操作。如果抛出一个异常,...
然而,一个重要的限制是,这些内部类只能访问在其作用域内的final或者实际上等效于final的局部变量。这是因为内部类可能在外部方法结束后仍然存活并访问这些变量,而普通的局部变量在方法执行完毕后就被销毁了。以下...
嵌套类主要分为两大类:**静态嵌套类**(Static Nested Class)和**内部类**(Inner Class)。这两类之间的主要区别在于它们是否可以访问外部类的实例变量。 ##### 2.1 静态嵌套类 - **定义**:被`static`关键字...
这种类型的内部类只能在定义它的方法或代码块中访问,并且可以访问该方法或代码块中的局部变量(局部变量必须是final的)。 综上所述,嵌套类提供了灵活的方式来组织和封装代码,使得代码更加清晰、安全且易于维护...
InnerClass01Test.java
局部内部类 Local inner 马克-to-win java视频的详细介绍
- **实例变量**:每个对象的副本都有各自的值,如`private final String S = "final实例变量S";`。 - **局部变量**:仅限于方法、构造器或块内的变量,也可以是`final`的。 示例代码: ```java public class Test3 ...
匿名内部类 inner class 马克-to-win java视频的详细介绍
* final域为引用类型:final域为引用类型时,访问顺序是:首先访问final域,然后访问非final域。 三、final的实现原理 final的实现原理是通过在编译期和运行期的特殊处理来实现的。在编译期,final域被编译器特殊...
本文详细介绍了Python中变量在函数中的作用域,主要包括局部变量的声明和作用范围、嵌套函数中的局部变量的作用范围以及如何在函数内部访问外层函数的变量。为了更好地理解和掌握这些概念,建议在实际的Python项目中...
匿名内部类 inner class 马克-to-win java视频的详细介绍
内部类(Inner Class)是Java语言中一个独特的特性,它允许在一个类的内部定义另一个类。这种设计模式在处理特定问题时提供了更大的灵活性,比如实现事件监听器、封装复杂逻辑或者创建私有的辅助类。本章我们将深入...