1.final是什么
final是一个java关键字,一个修饰符,可用于修饰变量,方法,修饰类.
2.final有什么用
- final可以修饰变量时,可以使其值不能改变
- final修饰方法时使其不能被重写
- final修饰类时,使其不能被继承.
3.final修饰成员变量
fianl最常见的用法时用来修饰成员变量,成员变量分为静态变量与普通变量.
对于final修饰的变量,不是不能被赋值,是其值不能被改变,可以理解成只能赋一次值.可以在定义时赋值,也可以在定义后在另外赋值,但无论何种方式只能被赋值一次.
(1)修饰静态变量
修饰静态变量时,可以选择以下两种方式赋值:
- 在定义时赋值
- 静态初始化块内赋值
final static int a = 6;
final static int b;
static
{
b = 6;
}
(2)修饰普通成员变量
修饰普通成员变量时,可以选择以下三种方式赋值:
- 定义时赋值
- 初始化块内赋值
- 构造方法赋值
public class test
{
int c = 1;
int d;
int e;
{
d = 2;
}
public test()
{
e = 3;
}
}
根据"静态"不能访问"非静态"规则,就是说静态的方法不能访问非静态成员,static初始化块不能初始化非静态成员,普通初始化块也不能初始化静态变量.
但是,有一个"bug"就是java允许通过方法访问final成员,因此…有趣的事情发生了.
public class test
{
final int a;
{
System.out.println(a);//这里会报错
printA();
a = 3;
printA();
}
void printA()
{
System.out.println(a);
}
public static void main(String[] args) {
new test();
}
}
以上这段代码会报错,因为java不允许final成员未初始化前访问.
把上面那一行出错的代码注释后…居然通过了编译?!
public class test
{
final int a;
{
//System.out.println(a);//这里会报错
printA();
a = 3;
printA();
}
void printA()
{
System.out.println(a);
}
public static void main(String[] args) {
new test();
}
}
printA()中只是用方法包装了一下输出函数,居然就通过了编译…有没有兴趣看一下结果?
emmmmmm…final"默认值"为0…总之就不要想这些歪门邪道去在final初始化之前访问final变量了 ,在使用final变量前初始化,初始化,初始化,重要的事情说三遍.
4.final修饰局部变量
final修饰局部变量其实也分两种,一种是修饰形参,一种是修饰方法内部的局部变量
(1)修饰形参
没什么好说的…就是形参的值不能改变.
public void f(final int a)
{
a = 3;//报错.
}
(2)修饰局部变量
修饰局部变量时可以定义时赋值,也可以在定义后在赋值(仅一次).
public void f()
{
final int a = 3;
final int b;
b = 2;
}
(3)final修饰引用变量
嗯…这个是一个特别一点的例子,Talk is cheap.上代码.
import java.util.Arrays;
public class test
{
public static void main(String[] args) {
final int[] arr = {1,2,3};
arr[1] = 5;
Arrays.stream(arr).forEach(System.out::print);
System.out.println();
final A a = new A();
a.setA(9);
System.out.println(a.getA());
}
}
class A
{
private int a = 3;
public void setA(int a)
{
this.a = a;
}
public int getA()
{
return a;
}
}
为什么final数组可以赋值???fianl对象的值被改变了???看看结果:
final数组居然被改变了??final对象的值也被改变了??
其实呢,因为数组是引用类型,final修饰引用类型时,只能保证这个变量永远"指向"那一段内存空间,保存的仅仅是一个引用,但是那段内存空间的值是可以改变的.修饰对象时也是一样的道理.
5.final修饰方法
final修饰的方法不能被重写,当然,不能"配合"private"使用",因为private把方法变成了私有,相当于对子类不可见,子类都不知道父类"还有这玩意",就可以进行所谓的"重写"了.
class A
{
private final void f(){}
}
class B extends A
{
public final void f(){}//没毛病
}
因为B类的f()是属于B类的,不是从A类继承过来的.
6.final修饰类
final修饰类时表示该类不能被继承.
final class A{}
class B extends A{}//出错