概述
final可以用来修饰数据、方法、类。
final数据
1、final修饰变量
final修饰基本数据类型的变量时,必须赋予初始值且不能被改变。
static final修饰的是常量,常量分为编译时常量与运行时常量,定义为static,强调只有一份。
比如static final int a = 10;就是编译时常量,只要是该常量带入的语句,在编译过后都会替换。
这段代码
在反编译后变成
而且只要这种常量在的算式,在编译时期就会被计算。(只有基本数据类型和String)
反编译后
很明显了。
关于运行时常量:static final int a = “123”.length();就是一个运行时常量,它的赋值会引起类的初始化。
编译器常量有一个风险。就比如A类定义了常量,B类使用了常量。但现在需要修改A类源码的常量值,对A类重新编译,但没对B类重新编译,这就导致A类与B类的常量值不一样。
2、final修饰引用
对于对象引用,final使引用恒定不变。就是一旦引用指向一个对象,就无法把他再指向另一个对象,但对象是可以修改的。数组也一样,毕竟数组也是对象。
3、空白final
所谓空白final就是被声明为final但未赋初值的域,但在使用前,必须保证赋初值,这样就可以灵活的为其进行赋值,但是又保持了其不可更改的特性 。
必须在域定义处(final修饰局部变量)或每个构造器里(final修饰成员变量)用表达式对final进行赋值。
public class Tests {
private final int j;
public Tests(){
j = 0;
}
public Tests(int x){
j = x;
}
public static void main(String[] args) {
new Tests(12);
final int k;
k = 2;
System.out.println(k);
}
}
3、final参数
被final修饰的参数称位final参数。意思是你无法更改参数引用所指向的变量,可以读参数,但不可修改参数。主要用于向内部类传递数据。
4、final方法
被final修饰的方法,只能被继承,不能被覆盖
final与private关键字:类中所有private方法都被隐式指定是final的,但如果在子类定义一个与父类方法名、参数列表、返回值都相同的private方法也可以,但调用的时候,还是按照private的法则,private方法只在本类中使用,而且用@Override也会报错,也就是说父类与子类的相同的private方法没有任何关系。
5、final类
当类被final修饰时,表示类是不可被继承的。final类中的所有方法都是隐式的指定为final的,无法被覆盖。但成员变量不是final,你可以人为指定某个成员变量是final。
继承与初始化
如下代码:
public class Battle extends Insect {
private int k = printInit("Battle.k initialized");
public Battle(){
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 = printInit("static Battle.x2 initialized");
public static void main(String[] args) {
System.out.println("Battle constructor");
Battle t = new Battle();
}
}
class Insect{
private int i = 9;
protected int j;
Insect(){
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 = printInit("static Insect.x1 initialized");
static int printInit(String s){
System.out.println(s);
return 47;
}
}
输出
在Battle上运行Java时,程序想要访问Battle类的main方法,这时加载器就要找出Battle的.class文件,对它进行加载。加载过程中,发现它有一个父类,于是就要对父类进行加载,如果发现父类还有父类,那就要加载“爷爷类”,不要认为加载父类是由于本类调用了父类的静态方法,实际上去掉调用父类的成员变量,父类还是先加载。
父类的static初始化完后,就轮到自己的static执行,执行完后,也就输出了前两行。
执行到这,说明必要的类已经加载完毕了。进入main方法,输出Battle constructor。开始创建对象。先把对象内所有的基本类型设置为默认值,引用类型设置为null(通过将对象内存设为二进制零值一举生成的),然后,构造器开始调用,我们知道,子类构造器会默认在第一行添加super(),先调用父类构造器,输出i = 9, j = 0;,然后子类构造器执行。
最后
以上就是玩命鸭子为你收集整理的final关键字/编译时常量与运行时常量/继承与初始化的全部内容,希望文章能够帮你解决final关键字/编译时常量与运行时常量/继承与初始化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复