final修饰符
1.final修饰变量
final修饰的变量指向是不可变的,比如string类型的数据,初始化就不可以改变了
例如:
public class FinalTest{
public static void main(String[] args) {
final String a = "str1";
a = "str2";
}
}
因为final修饰字符串所以a字符串是不可变的,所以上面代码编译是会报错的,原因是当a改变成str2的时候,引用变量指向会发生改变,注意为什么会在编译时候就会报错,因为JVM分配内存的时候将final视为不可变常量,既然是不可变常量,所以就会出现编译是报错,而不是运行时报错。
在分析一段代码:
public class FinalTest{
public static void main(String[] args) {
final String a = aaa();
final String b = "str";
String a1 = a +"2";
String a2 = a +"2";
String b1 = b +"2";
String b2 = b +"2";
System.out.println(b1 == b2);//结果true
System.out.println(a1 == a2);//结果false
}
static String aaa(){
return "str";
}
}
此时a,b同为final而且都是str为什么一个结果是true,一个是false,因为a并不是编译时就确定的变量,而是编译之后就确定的常量,而b编译时就确定常量,b1b2 string的生成是由两个常量生成的,所以引用变量指向一定是一样的
(相当于a1="str"+"2",a2="str"+"2"),而a1a2是由运行时常量生成所以两个地址是不一样的。但是如果将常量b的final去掉,那它的结果将会变成false,因为不是编译时就确定的
常量,所以他们他的指向就不一样。
如果修饰对象:
public class FinalTest{
public static void main(String[] args) {
final StringBuffer buffer = new StringBuffer("str");
buffer.append("a");
//buffer = new StringBuffer("str");//这句会报错
}
}
这段代码是正确的,虽然进行了值的修改,但是他的引用变量指向没有发生改变,因为buffer是一个
对象,只要对象指向没有发生改变就不会有错误,
如果在后面加上语句buffer = new StringBuffer("str");就会报错,这样会改便buffer的指向。
2.final修饰方法
这个没有特别好讲的,就是被final修饰的方法不能被子类重写。如果你想设定一个方法不能被子类继承就加上一个final。使用final就是为了不让子类继承。
注意:类的private方法会隐式地被指定为final方法。
3.final修饰的类
被final修饰的类不能被继承。
public class FinalTest extends Test{
public static void main(String[] args) {
}
}
final class Test{
}
编译时候就会报错,Test类是不能继承的。
4.final使用在方法内部类
public class FinalTest {
public static void main(String[] args) {
}
static void aaa(){
final int x = 1;//这里必须时final
class bbb{
void display(){
System.out.println(x);
}
}
}
}
x变量必须声明成final,当内部类使用方法中的变量x的时候会有一个
复制品产生,就是说会有一个private int x = 1;的变量在bbb内部类中,这样就会出现一定得问题,
问题就是局部变量的生命周期与局部内部类的生命周期的不一致性,也就是说,bbb类要使用x变量,如果aaa()方法调用结束,x可能被视为没有的数据就会被回收掉,一旦被回收掉,方法内部类不一定会被销毁,可能被其他引用没有被立刻销毁,又需要使用x,这时候就是出现内部类要访问一个不存在的局部变量。如果
不是final,就不能在内部类种使用,就无法保证复制品与原始变量保持一致了。因为,在方法中改的是原始变量,而局部内部类中改的是复制品。其实这些做法的根本原因都是为了维护复制品与原始变量的一致性。
总结来说,方法内部类使用final就是为了实现一致性。