基础:
1.修饰类
当用final修饰一个类时,表明这个类不能被继承,
基本类型所对应的包装类型 Byte,Short,Character,Integer,Long,Float,Double 都是 final 类。
final类中的成员变量可以根据需要设为final,但是,注意final类中的所有成员方法都会被隐式地指定为final方法
2.修饰方法
禁止该方法在子类被覆盖的情况下才将设置为final的。
3.修饰变量
对于一个final变量,如果是基本数据类型的变量,则其数值一旦初始化之后,便不能更改,
如果是引用类型的变量,则在对其初始化之后,便不能再让其指向另一个对象。
4.如果是static final变量,
可以在static代码块中初始化;如果没有static修饰符的话,可以在一般代码块中修饰。
5.final修饰其实是防止其被重新初始化 也就是被重新new 一个 或者被 = 赋值而已。
final类存储在常量池,存储在常量池的好处是有就引用没有创建,String s1="123"; String s2="123";s2不是重新赋值而是引用,final是常量值不可变,引用s1的值==所以会相等
二.深入理解
1.类的final关键字和普通变量有什么区别?
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。
public static void main(String[] args) {
String b= "hello0";
final int a = 0;
System.out.println(b == "hello" + a);
int c = 0;
System.out.println(b == "hello" + c);
String d = "0";
System.out.println(b == "hello" + d);
}
结果:
true
false
false
当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
2.被final修饰的引用变量指向的对象内容可变吗?
可变
3.final和static
static 作用于成员变量用来表示只保存一份副本,
而final的作用使用来保证变量不可变
public static void main(String[] args) {
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
System.out.println(myClass1.finalDouble);
System.out.println(myClass1.staticDouble);
System.out.println(myClass2.finalDouble);
System.out.println(myClass2.staticDouble);
}
public class MyClass {
public final double finalDouble = Math.random();
public static double staticDouble = Math.random();
}
4.关于final参数的问题
1 常量(final)的设置是不是只是为了防止程序员在以后修改程序时,忘记这个值是不能修改的?如果假设“程序员一定记得”这个值不允许改变,那么就可以不设为final吧?
程序员工作不是一个人的工作,你设置为final,别人将来维护的时候一看就知道这个变量不能修改,而不需要去记忆这个是不能变化的值,是常量。这个是代码规范。
另外final常量一般设置为static的,一定程度上节省了内存开销。
2 有些方法的参数中会声明参数为final,这样用有什么用? 例如 public A(final Map map);
参数声明为final就是标明这个对象的内存地址不允许修改。即就是如果你在方法里面修改为
map =new HashMap();是不允许的。但是map里面的值可以修改。
举一个例子
public class Test {
public static void main(String[] args) {
Map map = new HashMap();
process(map);
System.out.println(map.keySet().iterator().next());//结果输出aaa
}
private static void process(final Map map) {
map.put("aaaa", "1111");//尽管map为final,但是只是地址不变
//map里面的内容可以改变
//map = new HashMap();//当从新为final变量map分配内存地址,
//引起编译错误,因为final修饰的map内存地址不可以改变。
}
}
形象解析:参数加final
1、斯坦福教授说的好,方法可以比喻成一台机器(面包机),没错,在我的机器(方法)里面,我要的参数加了final(要原料),你给我传过来的参数,机器里面就无法改了,也就是说在机器里的这个参数,一直指向的都是你传进来的参数。
public class FinalNBA {
public static void main(String args[]) {
Curry curry = new Curry();
curry.setSmallName("small student");
printAll(curry);
System.out.println(curry);
}
public static void printAll(final Curry temp){
temp.setSmallName("fk do it");
System.out.println(temp.getSmallName());
// temp = new Curry(); 传送进来的Curry引用是final,不可以再赋值了,这里一定会报错哦!
}
}
2、总结,无论参数是基本数据类型,还是引用数据类型,只要加了final,不好意思,该参数不可以再赋值(实参传进来给形参,就相当于初始化完成)。。。。可以防止在方法里面不小心重新赋值,造成一些不必要的麻烦!!!
3、不加final的参数,可能会出现的错误是
public static void printAll(Curry temp){
temp = new Curry(); //这就是出现的问题,又new了一个库里,与调用该方法时传进来的库里毫无关系了!!
temp.setSmallName("fk do it");
System.out.println(temp.getSmallName());
}
参考资料:
https://blog.csdn.net/cadi2011/article/details/51615514/