final 关键字

在Java中,关键字final一般是指“无法改变的”。有三种情况可以使用到final:数据、方法、类。


1.final 数据

被final修饰的数据就是一个不能改变的常量。而一个既是static又是final的域则表示只占据着一段不能改变的存储空间。
对于基本数据类型,final使数值不能改变。比如我定义了如下几个常量:

	private final int valueOne = 9;
	private static final int VALUE_TWO = 99;
	public static final int VALUE_THREE = 39;


对于这几个常量,都不能改变它们的值——比如自加或者想尝试给它们赋值。
valueOne和VALUE_TWO并没有太大的区别,都可以用作编译期常量。而VALUE_THREE则是一种比较经典的常量定义方式,它表示是一个公有的并且只会初始化一次的常量。
注意,编译期常量的static final基本类型全用大写字母命名,并且字与字之间用下划线连接。
对于对象引用,final使引用恒定不变。一旦引用指向一个对象,便不能再指向另外的对象。但对象的值却可以改变。比如:

import java.util.Random;

class Value{
	int i;
	public Value(int i){
		this.i = i;
	}
}
public class FinalData {		
	
	private Value v1 = new Value(11);
	private final Value v2 = new Value(22);
	private static final Value VAL_3 = new Value(33);
	
	public static void main(String[] args) {
		FinalData fd1 = new FinalData("fd1");
	
                //fd1.v2 = new Value(0);       //不能使v2再指向其他对象
		fd1.v2.i++; //但可以改变v2所指向的对象中的值。
		fd1.v1 = new Value(9);//没有final修饰。
		//fd1.VAL_3 = new Value(1); //也不能使VAL_3指向其他对象
	}
}


因为数组也是对象,所以数组也符合上述所规定的情况:
	private final int[] a = {1,2,3,4,5,6};
		for(int i = 0;i<fd1.a.length;i++){
			a[i]++;		//数组中的对象的值依然可以改变
		}
		//a = new int[3];	//不能重新给a赋一个数组

空白final
空白final是指被声明为final却又未赋初值的域。但空白final必须在构造器中初始化:
public class BlankFinal {
	private final int i ;
	public BlankFinal(){
		i = 0;		//如果没有初始化,则会报错
	}
	public BlankFinal(int i){
		this.i = i;	//如果没有初始化,则会报错
	}
	
	public static void main(String[] args) {
		new BlankFinal();
		new BlankFinal(10);
	}
}

这样写,就可以使得一个类中的final域,可以根据不同的对象生成不同的值,并且还是不可变的。


final 参数
在一个方法中,可以将参数声明为final。但这样就无法改变参数引用所指向的对象或者参数的数值。
public class FinalArugment {
	public void f(final String s){
		//s = new String();	//报错
	}
	
	public void g(String s){
		s = new String();	//不会报错
	}
	
	void f(final int i){
		//i++;		//报错,不能改变其值
	}
	
	int g(final int i){
		return i+1;	//不会报错,可以读取i的值。
	}
}

2.final方法
使用final修饰的方法,可以防止任何继承类修改它,即在继承当中,这个方法不会被覆盖。
类中所有private方法都隐式地指定为final。
根据以上两句的总结,看如下一段代码:
class WithFinal{
	private final void f(){
		System.out.println("WithFinal.f()");
	}
	private void g(){
		System.out.println("WithFinal.g()");
	}
}


class OverrdingPrivate extends WithFinal{
	private final void f(){
		System.out.println("OverrdingPrivate.f()");
	}
	private void g(){
		System.out.println("OverrdingPrivate.g()");
	}
}


class OverrdingPrivate2 extends OverrdingPrivate{
	public final void f(){
		System.out.println("OverrdingPrivate2.f()");
	}
	public void g(){
		System.out.println("OverrdingPrivate2.g()");
	}
}


public class FinalOverridingIllusion {
	public static void main(String[] args) {
		OverrdingPrivate2 op = new OverrdingPrivate2();
		op.f();
		op.g();
		OverrdingPrivate op1 = op;
		//op1.f();	//不能调用
		//op1.g();	//不能调用 
		WithFinal wf = op;
		//wf.f();	//不能调用 
		//wf.g();	//不能调用
		
		
	}
}

以上代码看起来,子类好像覆盖了父类中的私有方法。但实际是却不是这样。
因为父类中的方法是由private修饰,所以其方法不属于基类中的接口的一部分,而覆盖是只有当方法是基类的接口的一部分时才会出现。因此,以上代码中的子类中,只是重新写了一个与父类方法同名的方法而已。

3 final类
当一个类由final修饰时,该类便不能再被继承。因而,这个类中的所有方法都会隐式地指定为final——反正都不能覆盖它们。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值