Java 基础之(六) final关键字
来源:互联网 发布:比较好的网红的淘宝店 编辑:程序博客网 时间:2024/05/20 09:48
Java中的final关键字非常重要,它可以应用于类、方法以及变量。
由于语境(应用环境)不同, final 关键字的含义可能会稍微产生一些差异。但它最一般的意思就是声明“这个东西不能改变”。之所以要禁止改变,可能是考虑到两方面的因素:设计或效率。
由于这两个原因颇有些区别,所以也许会造成 final 关键字的误用。
接下来,我们将讨论 final 关键字的三种应用场合:变量、方法以及类。
1. final变量
用final修饰的成员变量表示常量,值一旦给定就无法改变!
final变量经常和static关键字一起使用,作为常量。下面是final变量的例子:
public static final String LOAN = "loan";LOAN = new String("loan") //invalid compilation error
final变量是只读的。
定义为 public,则可以被用于包之外;定义为 static 来强调只有一份;定义为 final 来说明它是一个常量。
final标记的变量即成为常量,但这个“常量”也只能在这个类的内部使用,不能在类的外部直接使用。但是当我们用public static final 共同标记常量时,这个常量就成为全局的常量(一个既是static又是final的字段只占据一段不能改变的存储空间)。而且这样定义的常量只能在定义时赋值,其他地方都不行。
下面看个简单的例子:
public class Bat { final double PI = 3.14; // 在定义时赋值 final int i; // 因为要在构造函数中进行初始化,所以此处便不可再赋值 //在构造函数中为final变量分配初始值 Bat() { i = 100; } public static void main(String[] args) { Bat b = new Bat(); //b.i=25; System.out.println("I=" + b.i ); System.out.println("I=" + b.i ); }}
输出结果:I = 100;I= 100;
若去掉程序中注释的那行代码,则编译报错:无法最终变量i分配值。这说明i的值一旦初始化,确实无法更改。
除了在构造器中和定义时为final变量赋值外,也可以在普通初始化块中为其赋初始值。
除了上面的实例变量,final也可以用于修饰类变量。类变量只能在声明该变量时或静态代码块中赋初始值。
定义语法如下:
final static double d = 5.0;
final局部变量
看一个简单的例子:
public class TestFinalLocalVariable{ public void test(final int a) { //不能对final修饰的形参赋值,下面语句非法 //a = 5; } public static void main(String[] args) { //定义final局部变量时指定默认值,则str变量无法重新赋值 final String str = "hello"; //下面赋值语句非法 //str = "Java"; //定义final局部变量时没有指定默认值,则d变量可被赋值一次 final double d; //第一次赋初始值,成功 d = 5.6; //对final变量重复赋值,下面语句非法 //d = 3.4; }}
在上面程序中还示范了final修饰形参的情形。因为形参在调用该方法时,由系统根据传入的参数来进行初始化,因此使用final修饰的形参不能被赋值。
final引用变量
final修饰基本类型变量的时候,不能对基本数据类型变量重新赋值;但对于引用变量而言,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。
看一个例子:
class Person{ private int age; public Person(){} public Person(int age) { this.age = age; } public void setAge(int age) { this.age = age; } public int getAge() { return this.age; }}public class TestFinalReference{ public static void main(String[] args) { //final修饰数组变量,iArr是一个引用变量 final int[] iArr = {5, 6, 12, 9}; System.out.println(Arrays.toString(iArr)); //对数组元素进行排序,合法 Arrays.sort(iArr); System.out.println(Arrays.toString(iArr)); //对数组元素赋值,合法 iArr[2] = -8; System.out.println(Arrays.toString(iArr)); //下面语句对iArr重新赋值,非法 iArr = null; //final修饰Person变量,p是一个引用变量 final Person p = new Person(45); //改变Person对象的age属性,合法 p.setAge(23); System.out.println(p.getAge()); //下面语句对p重新赋值,非法 //p = null; }}
从上面程序可以看出,使用final修饰的引用变量不能被重新赋值,但可以改变引用类型变量所指向对象的内容。
宏变量
对一个final变量来讲,不管它是类field、实例field,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量,也称为宏变量。
- 使用final修饰符修饰
- 在定义该final变量时指定了初始值
该初始值可以在编译时就被确定下来
看如下程序:
public class TestFinal{ public static void main(String[] args){ //下面定义了5个宏变量 final int a = 5; final int i = 5+2; final double d = 1.2/3.0; final String str = "hello"+"world"; final String str1 = "hello" + 99.0; //下面str2变量的值因为调用了方法,因此无法在编译时被确定 final String str2 = "hello" + String.valueOf(99.0); System.out.println(str1 == "hello99.0"); System.out.println(str2 == "hello99.0"); }}
final修饰符的一个重要作用就是定义“宏变量”,编译器会把该程序中所有用到“宏变量”的地方直接替换成该变量的值。因此,执行下面这行代码时:
System.out.println(str);
实际执行的是System.out.orintln("helloworld");
程序最后两行分别判断str1和str2是否和“hello99.0”相等。由于str1是一个宏变量,它将被直接替换成“hello99.0”,因此返回true。
- final方法
之所以要使用 final 方法,可能是出于对两方面理由的考虑。
第一个是为方法“上锁”,防止任何继承类改变它的本来含义。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。
第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。
因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。
注:类的private方法会隐式地被指定为final方法。
final修饰的方法仅仅是不能被重写,并不是不能被重载。
3. final类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
Java中有许多类是final的,譬如String, Interger以及其他包装类。
class SmallBrain {}final class Dinosaur {int i = 7;int j = 1;SmallBrain x = new SmallBrain();void f() {}}//! class Further extends Dinosaur {}// error: Cannot extend final class 'Dinosaur'public class Jurassic {public static void main(String[] args) {Dinosaur n = new Dinosaur();n.f();n.i = 40;n.j++;}}
注意数据成员既可以是 final,也可以不是,取决于我们具体选择。应用于 final 的规则同样适用于数据成员,无论类是否被定义成 final。将类定义成 final 后,结果只是禁止进行继承—— 没有更多的限制。然而,由于它禁止了继承,所以一个 final 类中的所有方法都默认为 final。因为此时再也无法覆盖它们。所以与我们将一个方法明确声明为 final 一样,编译器此时有相同的效率选择。
可为 final 类内的一个方法添加 final 指示符,但这样做没有任何意义。
4.final的注意事项
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
5.final关键字的好处
- final关键字提高了性能。JVM和Java应用都会缓存final变量。
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
- 使用final关键字,JVM会对方法、变量及类进行优化。
参考:
http://blog.csdn.net/linchunhua/article/details/5305452
http://www.cnblogs.com/dolphin0520/p/3736238.html
http://lavasoft.blog.51cto.com/62575/18771/
http://www.tuicool.com/articles/qMzi6j
- Java 基础之(六) final关键字
- java基础之final关键字
- JAVA基础之final关键字
- Java基础之Final关键字
- Java基础之final关键字
- java基础之final关键字
- Java关键字(六)final与static
- java基础关键字之Static和final
- java基础之final关键字作用
- java基础语法之final关键字
- java基础(三)之final关键字
- Java基础: 关键字 final
- final关键字 -----JAVA基础-------
- Java基础----final关键字
- [Java基础] final关键字
- java基础-final关键字
- java基础--final关键字
- JAVA 基础 final关键字
- apache模块mod_rpaf ,让nginx后端的apache获取访客IP
- error_reporting() 设置 PHP 的报错级别并返回当前级别
- Adapter模式
- Plus One
- struts2中getOutputStream() has already been called for this response异常解决方法
- Java 基础之(六) final关键字
- 通过Spring @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
- php的empty函数参数不能是一个函数
- 修改CentOs7 上Docker默认文件系统DeviceMapper为OverlayFS
- 函数参数前是否加&的问题
- replicate_do_db和repalicate_wild_do_table跨库同步问题
- Spring4 Bean管理的注解实现
- Mob的ShareSDK
- php递归函数相关知识