首先为了大家清楚掌握final关键字的重要性,先上几道面试题给大家看看
- 提前批百度一面
16、final的作用- 滴滴一面
4.说一下重载和重写, 重写要注意什么(俩小俩等一大) final修饰方法可以重写吗, static方法可以重写吗,- 北森测试开发
final:string可以被继承吗(我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承)
final可以修饰抽象类吗
final关键可以用来修饰变量、成员方法以及类。
- 修饰变量或字段,表示常量(即不能修改)
- 修饰成员变量(如果引用是类的成员变量,则必须当场赋值,否则编译会报错。)
- 如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。
- 如果final修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中进行初始值。
- 修饰局部变量
系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化,因此使用final修饰局部变量时,既可以在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋值(仅一次)
public class FinalVar {
final static int a = 2 ; //在静态初始化块中指定初始值或者声明该类变量时指定初始值
static {
// a=2;
}
final int b = 3; //在非静态初始化块、声明该变量或者构造器中进行初始值
{
// b =3;
}
// public FinalVar(int b) {
// this.b = b;
// }
public static void main(String[ ]args) {
final int localA;//局部变量只声明没有初始化,不会报错,与final无关
localA = 0; //只使用之前一定要赋值
// localA = 3; 但是不允许第二次赋值
System.out.println(localA);
}
}
- 修饰基本类型数据和引用类型数据
- 如果是基本类型的变量,则其数值一旦初始化之后就不能更改。
- 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,但是引用的值是可以改变的。
- 注:final修饰的常量在编译阶段会被放入常量池中。
public class FinalReferenceTest {
public static void main(String []args) {
final int[] iArr = {1,2,3,4};
iArr[2] = -3;
// iArr = null; //非法,对iArr不能重新赋值
final Person p = new Person(25);
p.setAge(66);//合法
// p =null; //非法
}
}
- 修饰类:表示此类不能被继承
我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承.
当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承。
使用final方法的原因主要有两个:
(1)把方法锁定,以防止继承类对其进行更改
(2)效率,在早期的java版本中,会将final方法转为内嵌调用。但若方法过于庞大,可能在性能上不会有多大提升。因此在最近版本中,不需要final方法进行这些优化了
final方法意味着“最后的、最终的”含义,即此方法不能被重写。
注意:若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。
public class Test {
//编译之后会生成连个class文件,Test.class Test1.class
public static void main(String[] args) {
Test t = new Test();
t.test(20);
}
//局部final变量a,b
public void test(final int b) {
final int a = 10;
new Thread() {
public void run() {
System.out.println(a);
System.out.println(b);
};
}.start();
}
}
public class OutClass {
private int age = 12;
public void outPrint(final int x) {
class InClass {
public void InPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
首先需要知道的一点是: 内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的
执行完毕就被销毁
这里就会产生问题,当外部类的方法结束时,局部变量就会被销毁了,但是内部类对象可能还存在(只有没有人再引用它时,才会死亡)。这里就出现了一个矛盾,==内部类对象访问了一个不存在的变量,为了 解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类仍然可以访问它,实际访问的是局部变量的"copy",==这样就好像延长了局部变量的生命周期。将局部变量复制为内部类的成员变量时,必须保证这两个变量时一样的,也就是如果我们在内部类修改了成员变量,方法中的局部变量也得跟着改变,怎么解决问题呢?
就将局部变量设置为final,对它初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性,这实际上也是一种妥协,使得局部变量与内部类建立的拷贝保持一致。
总结:外部类的成员变量,可能其实已经销毁了,内部类访问的只是它的拷贝,所以防止内部类修改值,就将 成员变量用 final修饰