再说java final变量
http://blog.csdn.net/axman/article/details/1460544 从jdk1.0到今天,JAVA技术经过十余年的发展,技术上已经发生了巨大的变化.但final变量的定义从它
诞生那天起,就没有发生任何变化,也就是这十多年它就一直表示它原来的意思.
但遗憾的是,经过十多年仍然有90%的人没有理解它的真实含义,也没有一篇文章,包括我所见到的所有介绍
JAVA的书籍(包括TKJ)都没有说清楚,我相信肯定有些作者是理解的,但没有一个作者向读者说清楚.而中国网友
大多数人被一篇胡说八道的<<浅谈Java中final,finalized,finally>>的文章跑过马.(脸红一下:当初我也是).
final变量的定义本身并不复杂,就是变量一经初始化就不能再指向其它对象.在c++中它是一个const指针,而
不是指向const变量的指针,const指针的意思是说它只能一直指向初始化时的那个地址.但那个地址中对象本身
是可以修改的.而指向const变量的指针是说所指对象本身是不能修改的.
如:final StringBuffer sb = new StringBuffer("Axman");
sb = new StringBuffer("Sager");//错误,sb不能再指向其它对象.
sb.append(" was changed!"); //sb指向的地象本身可以修改.
先说final变量初始化:
很多文章都这么说:其初始化可以在两个地方,一是其定义处,二是在构造函数中,两者只能选其一。
胡说八道!
final变量可以在任何可以被始化的地方被始化,但只能被初始化一次.一旦被初始化后就不能再次赋
值(重新指向其它对象),作为成员变量一定要显式初始化,而作为临时变量则可以只定义不初始化(当然也不能引用)
即使是作为一个类中的成员变量,也还可以在初始化块中初始化,所以"其初始化可以在两个地方,一是其定义处,
二是在构造函数中,两者只能选其一"是错误的.
作为成员变量时,final字段可以设计不变类,是不变类的一个必要条件但不是一个充要条件.至少可以保证字段不
会以setXXX()这样的方式来改变.但无法保证字段本身不被修改(除非字段本身也是不变类);
对于方法参数的final变量:
对于方法参数的变量定义为final,90%以上的文章都说"当你在方法中不需要改变作为参数的对象变量时,明确使
用final进行声明,会防止你无意的修改而影响到调用方法外的变量。"
胡说八道!
我不知道这个修改是说重新赋值还是修改对象本身,但无论是哪种情况,上面的说法都是错误的.
如果是说重新赋值,那么:
public static void test(int[] x){
x = new int[]{1,2,3};
}
int[] out = new int[]{4,5,6};
test(out);
System.out.println(out[0]);
System.out.println(out[1]);
System.out.println(out[2]);
调用test(out);无论如何也不会影响到外面变量out.你加不加final根本没有意义.final只会强迫方法内
多声明一个变量名而已,即把x = new int[]{1,2,3};改成int y = new int[]{1,2,3}; 其它没有任何实际意义.
如果说是修改对象本身:
public static void test(final int[] x){
x[0] = 100;
}
int[] out = new int[]{4,5,6};
test(out);
System.out.println(out[0]);
难道你用final修饰就不可以修改了?所以说对于方法参数中final是为了不影响调用方法外的变量那是胡说八道的.
那我们到底为什么要对参数加上final?其实对方法参数加final和方法内变量加上final的作用是相同的,即为了将它们
传给内部类时保证调用的一致性:
abstract class ABSClass{
public abstract void m();
}
现在我们来看,如果我要实现一个在一个方法中匿名调用ABSClass.应该:
public static void test(final String s){
//或final String s = "axman";
ABSClass c = new ABSClass(){
public void m(){
int x = s.hashCode();
System.out.println(x);
}
};
//其它代码.
}
从代码上看,在一个方法内部定义的内部类的方法访问外部方法内局部变量或方法参数,是非常自然的事,但内部类编译的时候如何获取这个变量,因为内部类除了它的生命周期是在方法内部,其它的方面它就是一个普通类。那么它外面的那个局部变量或方法参数怎么被内部类访问?编译器在实现时实际上是这样的:
public static void test(final String s){
//或final String s = "axman";
class OuterClass$1 extends ABSClass{
private final String s;
public OuterClass$1(String s){
this.s = s;
}
public void m(){
int x = s.hashCode();
System.out.println(x);
}
};
ABSClass c = new OuterClass$1(s);
//其它代码.
}
即外部类的变量被作为构造方法的参数传给了内部类的私有成员.
假如没有final,那么:
public static void test(String s){
//或String s = "axman";
ABSClass c = new ABSClass(){
public void m(){
s = "other";
}
};
System.out.println(s);
}
就会编译成:
public static void test(String s){
//或String s = "axman";
class OuterClass$1 extends ABSClass{
private String s;
public OuterClass$1(String s){
this.s = s;
}
public void m(){
s = "other";
}
};
ABSClass c = new OuterClass$1 (s);
}
内部类的s重新指向"other"并不影响test的参数或外部定义的那个s.同理如果外部的s重新赋值内部类的s也不会跟着改变。
而你看到的
public static void test(String s){
//或String s = "axman";
ABSClass c = new ABSClass(){
public void m(){
s = "other";
}
};
System.out.println(s);
}
在语法上是一个s,在内部类中被改变了,但结果打印的出来的你认为是同一的s却还是原来的"axman",
你能接收这样的结果吗?
所以final从语法上约束了实际上两个不同变量的一致性(表现为同一变量).
再说java final变量的更多相关文章
- Java基础-内部类-为什么局部和匿名内部类只能访问局部final变量
先看下面这段代码: public class Test { public static void main(String[] args) { } public void test(final int ...
- 【JAVA】在编译期可直接替换的final变量
一.满足以下三个条件,一个final变量就不再是一个变量,而是一个直接量. 使用final修饰符修饰. 在申明的时候就进行初始化 初始化的值在编译器就可以确定. 二.在什么情况下初始化的值在编译期是可 ...
- java的final变量理解
java的final变量理解 final基本类型是数值不能改变 final对象是引用不能改变,对象其自身是可以被修改的.
- java final修饰变量时的一种情况
有如下一种场景. 1.在文件PaymentConfig.java中存在如下变量public static final desc="描述" 2.类Test.java中使用了desc变 ...
- Java final 关键词修饰类、方法、变量
1. final修饰类 被修饰的类不能被继承,也没有子类.假如随意创建这些类的子类,子类可能会错误的修改父类的实现细节.出于安全原因,类的实现细节不允许有任何改动.在创建对象模型的时候,确信这个类不 ...
- Java基础-final变量和普通变量的区别
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再 ...
- Java中final变量的初始化方式
原文转自:http://blog.csdn.net/zhangjk1993/article/details/24196847 public class FinalTest1 { //--------- ...
- java中final变量的用法
4.4 final变量 final变量的数值不能在初始化之后进行改变(你希望a=3,有很多用到a的场合, 你当然不能在程序中就用3来代替a). 比如: final int h = 0; 想像有一 ...
- java中变量命名和引用变量的一个坑
这次有两个主题,第一个太简单啦,就是java中变量的命名规则,纯记忆性东西.第二个主题,就是讨论一下对象引用变量的一个注意点.
随机推荐
- 自己搭建了一个blog
https://svtt.sinaapp.com 利用JustWriting开源项目搭建的,不过还是有些许问题.但是考虑到自己的blog好处多多,暂且用着--有时间或者乐趣来了,自己再用wordpre ...
- docker 集群 kubernetes 1.8 构建
1.环境说明:操作系统:CentOS7Kubernetes 版本:v1.8.3Docker 版本:v17.06-ce master 192.168.10.220 etcd kube-apiser ...
- [暑假集训--数论]poj2142 The Balance
Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. F ...
- 【12】react 之 redux(1)
TodoList小demo 效果展示 项目地址 (单向)数据流 数据流是我们的行为与响应的抽象:使用数据流能帮我们明确了行为对应的响应,这和react的状态可预测的思想是不谋而合的. 常见的数据流框架 ...
- linux之创建临时文件的方法
有时候,我们需要创建文件临时存放一些输出的信息,创建文件时就可能出现文件名存在的问题.如何创建唯一的文件名,Linux为我们提供几个方案: 1.mktemp(强烈推荐) The mktemp ut ...
- JavaScript计算字符串中包含几个给定字符
原文发布时间为:2009-05-04 -- 来源于本人的百度文章 [由搬家工具导入] 下面以 逗号 为例子: <html> <head><title>JavaScr ...
- 【DirectX SDK Extra】提示缺少Qedit.h问题 (转)
原文转自 http://blog.csdn.net/joeblackzqq/article/details/10944005 DirectX 9.0 SDK 开发包以及扩展包下载(February 2 ...
- centos7下mysql双主+keepalived
一.keepalived简介 keepalived是vrrp协议的实现,原生设计目的是为了高可用ipvs服务,keepalived能够配置文件中的定义生成ipvs规则,并能够对各RS的健康状态进行检测 ...
- NLP--edit distance
基本思想 通过插入(insert).删除(delete)和替换(substitute)个操作将一个字符串s1变换到另一个字符串s2的最少步骤数distacnce,用(1-distance/length ...
- Codeforces 911F Tree Destruction(贪心 && 树的直径)
题目链接 Tree Destructi 题意 给定一棵树,每次可以选定树上的两个叶子,并删去其中的一个.答案每次加上两个选定的叶子之间的距离. 求最后答案的最大值. 首先求出树的某一条直径,令其端 ...