final关键字
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了final关键字相关的知识,希望对你有一定的参考价值。
final修饰的变量
被final修饰的变量一旦被赋初始值,final变量的值以后将不会被改变。
被final修饰的实例变量必须显示指定初始值,且只能在3个位置指定初始值:
1.定义final实例变量时指定初始值
2.在非静态初始化块中为final实例变量指定初始值
3.在构造器中为final实例变量指定初始值
public class FinalInstanceVaribaleTest { final int var1 = "var1".length(); final int var2; final int var3; { var2 = "var22".length(); } public FinalInstanceVaribaleTest(){ this.var3 = "var333".length(); } }
但本质上还是在构造器中被赋初始值(经过编译器的处理)。
对于final类变量而言,同样必须显示指定初始值,只能在2个地方制定
1.定义final类变量时指定
2.在静态初始化块中指定
public class FinalClassVaribaleTest { final static int var1 = "var1".length(); final static int var2; static{ var2 = "var22".length(); } }
本质上实在静态初始化块中赋初始值。
对于局部变量来说更为简单,Java本来就要求局部变量必须被显示地赋初始值。
对于一个final变量,不管是类变量、实例变量、局部变量,只要定义该变量时使用了final修饰符修饰,并且定义该final类变量时指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个直接量。
public class FinalLocalTest { public static void main(String[] args) { final int a = 2; System.out.println(a); } }
实质上,a就成为了一个"宏变量"(在编译时就可确定的值),再用到a的时候直接以2来代替。
public class FinalTest { public static void main(String[] args) { final int a = 5 + 2; final String str = "s" + "tr"; final String book1 = "book1:" + 99.0; //下面的book2因为调用了方法,所以无法在编译时被确定下来 final String book2 = "book2:" + String.valueOf(99.0); System.out.println(book1 == "book1:99.0"); System.out.println(book2 == "book2:99.0"); } }
此时book2就不是"宏变量",所以输出为true false
对于实例变量而言,有三种方法可以赋初始值,但对于final实例变量而言,只有在定义该变量时指定初始值才会有"宏变量"的效果。
public class FinalInitTest { final String str1; final String str2; final String str3 = "str"; { str1 = "str"; } public FinalInitTest(){ str2 = "str"; } public void display(){ System.out.println(str1 + str1 == "strstr"); System.out.println(str2 + str2 == "strstr"); System.out.println(str3 + str3 == "strstr"); } public static void main(String[] args) { FinalInitTest fit = new FinalInitTest(); fit.display(); } }
结果为:flase,false,true
对于final类变量也是如此,只有在定义类变量时指定初始值,才会变为"宏变量"。
final方法不能被重写
如果父类中的某个方法被final修饰符进行修饰,那么这个方法不可能被子类访问到,因此这个方法也不会被子类重写。
class Parent{ private final void a(){ System.out.println("P-->a"); } } public class Children extends Parent{ public void a(){ //这个a方法并不是覆盖父类方法,而是定义的一个普通方法 System.out.println("C-->a"); } }
如果想要测试是否为覆盖(重写),可在方法前加@Override(一个工具注释)。
与此类似的还有父类子类不在同一个包下,访问修饰符为private或默认,也是无法重写的。
final修饰的类无法被继承
一些常用的类:String、Math、System等等。
在任何内部类中访问的局部变量都应该使用final修饰。
interface IntArrayProductor{ int product(); } public class CommanTest{ //定义一个方法生成指定长度的数组,但每个数组元素由cmd负责产生 public int[] process(IntArrayProductor cmd,int length){ int[] result = new int[length]; for(int i = 0;i < length;i++){ result[i] = cmd.product(); } return result; } public static void main(String[] args) { CommanTest ct = new CommanTest(); final int seed = 5; int[] result = ct.process(new IntArrayProductor() { public int product(){ return (int)Math.round(Math.random() * seed); } },6); System.out.println(Arrays.toString(result)); } }
此时seed变量必须被final修饰(否则会出现编译错误),不过我在jdk1.8运行没有final也可以,有可能是新加的特性吧。
此处所说的内部类为局部内部类(包括匿名内部类),因为只有其可以访问局部变量,普通静态内部类、非静态内部类都不可能访问方法体内的局部变量。
以上是关于final关键字的主要内容,如果未能解决你的问题,请参考以下文章