java关键字final用于修饰数据、方法或类,通常意味着“无法改变的”,既数据不能改变,方法不能覆盖,类不能继承。一般采用final有两种原因:设计和效率。而随着java版本的更新,一些效率上的问题可以交由编译器和jvm处理。因此,采用final来解决效率问题就显得不是那么重要了。
final修饰符大多运用于基本数据类型(primitive)域或者不可变(immutable)类的域(如果类中的所有方法方法都不会改变其对象,这种类就是不可变类。string就是一个不可变类)。
【final数据】
final关键字用修饰数据主要有两种情况:
1. 编译期常量
2. 运行时初始化的值
对于编译期常量,指的是一个既是final又是static的域(依照惯例,编译期常量全部用大写字母命名,并且用下划线分隔各个单词),它只占据一段不能改变的存储空间。编译器可以将编译期常量代入到任何可能用到它的计算式中,也就是说,可以在编译时执行计算式,这相对减轻了运行时负担。编译期常量在定义时必须对它赋值(不一定是基本类型)。
运行时初始化的值,对于基本类型,final使得其值不可改变;而对于对象引用,final使得引用不可改变,即无法将其改为指向另一个对象,然而,对象本身却可以修改(适用于数组,数组也是对象)。
代码如下:
public class javafinaldata{ private static final string testd = "test"; public static final string teste = "test"; public static final string[] testf = {"1","2"}; //非基本类型 private static final string[] testg = new string[2]; public static void main(string args[]){ final int testa = 1; final string testb = "test"; final int[] testc = {1,1,2,}; system.out.println(testc[1]); testc[1] = 123; system.out.println(testc[1]); } }
【未赋值的final域】
java允许生成未赋值的final域,但是必须在域的定义处或者每个构造器中对final域进行赋值(有多少个构造器就必须赋值几次),确保在使用前被初始化。采用这种方式,可以使得final运用得更加灵活,在同一个类中,根据不同的对象赋予不同的值,却又保持不可改变的特性。
代码如下:
public class javablankfinal{ private final int blank; public javablankfinal(){ blank = 2011; } public javablankfinal(int temp){ blank = 2012; } public javablankfinal(string temp){ blank = 2014; } public static void main(string args[]){ new javablankfinal(); } }
【final方法】
使用final方法有两方面原因:一是将方法锁定,防止方法被覆盖,确保在继承中方法行为保持不变;二是将方法调用转为内联调用(inlining),以减少方法调用的开销。但是,在最近的版本中,jvm可以自行进行优化,因此无需使用final方法来处理效率问题。
关于final方法,还有一点需要注意,类中所有的private方法都隐式地指定为final方法(也可以为其加上final修饰,但没有意义)。当你试图覆盖一个private方法,编译器并没有报错,但是,实际上你并没有覆盖该方法,只是生成了一个新方法。因为private方法是无法被外部类所访问的,当然就无法覆盖到它了。
使用@override注解可以防止上述问题。如程序所示:
代码如下:
class finalfunction{ private void finalfunctiona(){ system.out.println("finalfunctiona"); } private final void finalfunctionb(){ system.out.println("finalfunctionb"); } final void finalfunctionc(){ system.out.println("finalfunctionc"); } void functiond(){} } class overridefinalfunction extends finalfunction{ //@override 添加@override注解可以识别是否是override public void finalfunctiona(){ system.out.println("override finalfunctiona"); } public final void finalfunctionb(){ system.out.println("override finalfunctionb"); } //final void finalfunctionc(){} //cannot override the final method from finalfunction @override void functiond(){} //真正的override方法 } public class javafinalfunction extends finalfunction{ public static void main(string args[]){ finalfunction ff = new finalfunction(); //ff.finalfunctiona(); //无法调用private方法 //ff.finalfunctionb(); overridefinalfunction off = new overridefinalfunction(); off.finalfunctiona(); //public方法 off.finalfunctionb(); } }
【final类】
使用final类一般是出于设计原因,不允许该类被继承。这样可以保证类的行为不会改变,或许还能避免一些安全危机。final类中所有的方法都隐式指定为final方法,因此无法被覆盖(因为final类禁止继承,也就无法覆盖其类中的方法)。在java核心api中,有许多应用final的例子,例如java.lang.string。为string类指定final防止覆盖length()等方法。
对于final域来说,即使将一个类声明为final,类中的域不会自动成为final域。
代码如下:
final class finalclass{ int testa = 2011; } //class extendfinalclassextends finalclass{} //can not extendthe final class finalclass public class javafinalclass{ public static void main(string args[]){ finalclass fc = new finalclass(); system.out.println(fc.testa); fc.testa = 2012; system.out.println(fc.testa); } }
以上就是深入java final的详细内容。
