解析final关键字

基础:

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/

猜你喜欢

转载自blog.csdn.net/qq_32363305/article/details/81166162