A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 曾_强 中级黑马   /  2012-5-14 13:48  /  2347 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文


如题。有一个疑问:

final关键字到底修饰了什么?  

final使得被修饰的变量"不变",但是由于对象型变量的本质是“引用”,使得“不变”也有了两种含义:引用本身的不变和引用指向的对象不变。 具体是什么?

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1

查看全部评分

6 个回复

倒序浏览
可见,final只对引用的“值”(也即它所指向的那个对象的内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。这很类似==操作符:==操作符只负责引用的“值”相等,至于这个地址所指向的对象内容是否相等,==操作符是不管的。

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
final修饰的那个变量不能再被赋值,如果他指向了一个对象,那个对象中的值当然是可以变的
回复 使用道具 举报
引用本身的不变:
final StringBuffer a=new StringBuffer("immutable");
final StringBuffer b=new StringBuffer("not immutable");
a=b;//编译期错误

引用指向的对象不变:
final StringBuffer a=new StringBuffer("immutable");
a.append(" broken!"); //编译通过
//将给定文本追加到文本区的当前文本。


可见,final只对引用的“值”(也即它所指向的那个对象的内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误 。至 于它所指向的对象的变化,final是不负责的。这很类似==操作符:==操作符只负责引用的“值”相等,至于这个地址所指向的对象内容是否相等,==操 作符是不管的。

理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象,不能保证那个对象的状态不变。在多线程的操作 中,一个对象会被多个线程共享或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它 声明为final,意图使得它“永远不变”。其实那是徒劳的。

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
final只对引用的“值”(也即它所指向的那个对象的内存地址)有效
回复 使用道具 举报
本帖最后由 廖理 于 2012-5-14 14:46 编辑

这里从两个方面来说明Final修饰的变量问题
关键:
1.final修饰基本数据类型:
首先简单理解啊,比如final int X = 4;之后X还能被赋值吗?显然是不能的。原因就是final修饰的是基本类型的变量,
基本数据了类型的变量必须在定义时就被初始化。而且初始化之后不能再改变,此时x中存放的是4这个值。不能再改变。

2.final修饰基本数据类型:
这里以StringBulider为例来说明
对于final修饰的对象引用当然也只能被赋值一次啦
所以final StringBulider  a=new StringBulider ("dsdsfddsfds")中的a不能再被赋值。

当然实质上,final 修饰的是 一个对象的引用,引用中存放的是一个地址值,所以当然是a中存放的地址不能改变,
即a不能再指向StringBuffe的其他对象,而a当然可以调用自己的公有成员方法a.append(" fdsf");类虽然发生了变,
但a中地址并没有改变,所以只要对象的引用(地址)没有改变,对象的内容是可以改变的。

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
荣天 中级黑马 2012-5-14 21:32:29
7#
final方法
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。

final类
当你将final用于类身上时,你就需要仔细考虑,因为一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但这显然没有意义。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马