Java语言中的final关键字,想必你们都不是很陌生,咱们本身用的最多的应该是用来定义常量吧,那么今天咱们就来了解final这个关键字的用法,这个关键字仍是很是简单的。html
final从字面意思是不可更改的,最终的意思,它能够用来修饰类、方法、变量(包括成员变量和局部变量)、参数。优化
final修饰类,表示该类不能再被继承了,若是一个类它的功能比较完整,不须要扩展功能,咱们就可使用final来修饰。咱们最经常使用String、Integer、System等类就是用final修饰的,其不能再被其余类所继承。this
用final修饰类若是被继承了那么在编译的时候就会报错。spa
final修饰方法,表示这个方法不能被子类方法重写。若是你认为一个方法的功能已经足够完整了,不须要再去子类中扩展的话,咱们能够声明此方法为final。好比Object类中getClass()方法就是final修饰的。code
注意:类中全部的private方法都自动成为final。因为不能访问一个private方法,因此它绝对不会被覆盖。htm
final修饰变量表示是常量,通常都和static一块儿使用,用来定义全局常量。final不管修饰的是成员变量仍是局部变量,都必须进行显式初始化,以下。对象
1 public class FinalTest { 2 //显式初始化 3 final int AA=11; 4 final int BB; 5 final int CC; 6 final int DD; 7 //构造代码块初始化 8 { 9 BB=22; 10 } 11 //构造方法初始化 12 public FinalTest(){ 13 CC=33; 14 DD=44; 15 } 16 17 public FinalTest(int CC, int DD) { 18 this.CC = CC; 19 this.DD = DD; 20 } 21 }
咱们能够经过显式初始化、构造代码块初始化、构造方法初始化这三种方式对final修饰的变量进行初始化。blog
前面都是讲的final修饰基本数据类型的变量,若是final修饰引用变量会是怎么样,咱们来看一下举例:继承
1 public class FinalTest { 2 3 public static void main(String[] args) { 4 final AA aa = new AA(); 5 //这里在引用其余的对象就会报错Cannot assign a value to final variable 'aa' 6 //aa=new AA(); 7 aa.i++; 8 System.out.println(aa.i); 9 } 10 11 } 12 13 class AA{ 14 int i; 15 } 16 17 //运行结果:1
能够看到,虽然咱们将引用变量用final修饰了,可是该对象的变量 i 咱们仍是能够进行修改,而这个变量的引用不能再指向另外一个对象了。代表final修饰的是引用变量,就不能再指向其余对象,可是若是该对象内的变量不是final修饰的,其变量的值是能够进行修改的。get
final修饰参数准确的来讲应该是修饰形参,代表该形参的值不能被修改。
1 public class FinalTest { 2 3 public static void main(String[] args) { 4 FinalTest f=new FinalTest(); 5 f.show(5); 6 } 7 8 public void show(final int param){ 9 //编译报错:Cannot assign a value to final variable 'param' 10 //param=10; 11 System.out.println(param); 12 } 13 }
我在使用final修饰形参时,代表此形参是一个常量。当咱们调用方法的时候,给形参进行赋值,一旦赋值之后,就只能在该方法使用,并且不能进行从新赋值操做,不然编译报错。若是形参是引用类型,则引用变量不能再指向其余对象,可是该对象的内容是能够改变的。
参考连接:http://www.javashuo.com/article/p-heipsycl-n.html
当用final做用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只须要保证在使用以前被初始化赋值便可)必须在定义时或者构造器中进行初始化赋值,并且final变量一旦被初始化赋值以后,就不能再被赋值了。那么final变量和普通变量到底有何区别呢?下面请看一个例子:
1 public class Test { 2 public static void main(String[] args) { 3 String a = "hello2"; 4 final String b = "hello"; 5 String d = "hello"; 6 String c = b + 2; 7 String e = d + 2; 8 System.out.println((a == c)); 9 System.out.println((a == e)); 10 } 11 }
输出结果:true、false
你们能够先想一下这道题的输出结果。为何第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,若是在编译期间能知道它的确切值,则编译器会把它当作编译期常量使用。也就是说在用到该final变量的地方,至关于直接访问的这个常量,不须要在运行时肯定。这种和C语言中的宏替换有点像。所以在上面的一段代码中,因为变量b被final修饰,所以会被当作编译器常量,因此在使用到b的地方会直接将变量b 替换为它的值。而对于变量d的访问却须要在运行时经过连接来进行。想必其中的区别你们应该明白了,不过要注意,只有在编译期间能确切知道final变量值的状况下,编译器才会进行这样的优化,好比下面的这段代码就不会进行优化:
1 public class Test { 2 public static void main(String[] args) { 3 String a = "hello2"; 4 final String b = getHello(); 5 String c = b + 2; 6 System.out.println((a == c)); 7 8 } 9 10 public static String getHello() { 11 return "hello"; 12 } 13 }
这段代码的输出结果为false。这里要注意一点就是:不要觉得某些数据是final就能够在编译期知道其值,经过变量b咱们就知道了,在这里是使用getHello()方法对其进行初始化,他要在运行期才能知道其值。