Java中final的用法

Java中,final可以修饰类,方法,属性。

final数据

final关键字修饰变量,用来向编译期告知这块数据恒定不变:

1.一个永不改变的编译期常量:Java中这类常量必须是基本类型,编译期可以将该常量代入到可能用到它的表达式中,也就是说,可以在编译期执行计算;

 private final int valueOne = 1;
 public static final int VALUE_TWO = 2;

 

2.一个运行期时被初始化的值,一旦初始化完成,将不再改变。

private final  Random rand = new Random(100);
private final int valueThree =rand.nextInt(50);

final修饰的是对象引用时,要特别注意一定:该引用不能改变,但是该引用指向的对象却可以修改。这一限制同样适用于数据,它也是对象。

//无法将r再指向另外一个新的对象,array也不能指向新的数组
private final Refe r = new Refe(23);
private int[] array = {1,2,3,4,5,6};

public void changeFinalRefeObject() {
	//编译无法通过,不允许修改r
	//r = new Refe(22);
	
	//但是修改r所指向的对象却是可以的
	r.age = 22;
	
	//编译无法通过,不允许修改array
	//array = new int[6];
	
	//修改数组的内容却是可以的
	array[0] = 10;
}

 

 

空白final(没在定义处给出值),需要注意一些,但是稍加思考,都是符合逻辑的:

1.static finalstatic final是类变量,且只能初始化一次,所以这类变量这能在静态语句块中初始化;

public static final int VALUE_ONE;
//只能在静态语句块中初始化
static {
    VALUE_ONE = 1;
}

 

2.static final:非静态语句块先于构造方法执行,所以可以在非静态语句块中对final变量赋值;

private final int valueOne;
//在执行构造方法前,先执行非静态语句块
{
	valueOne = 1;
}

 

3.如果在构造方法中对final变量赋值的话,所有的构造方法都必须有对final变量的赋值语句;

class Final {
	private final valueOne;
	
	public Final() {
		valueOne = 1;
	}
	
	public Final(int xx) {
		valueOne = 1;
	}
}

 

 

4.不能同时在非静态语句块和构造方法中对final赋值,因为只能初始化一次,但是语句块总是和构造方法一同执行。

 

总之记住一点:final修饰的变量在使用之前,必须初始化,只有三个地方可以初始化:

a.定义处初始化;

b.语句块中初始化;

c.构造方法中初始化。

final还可以修饰参数,无法修改参数的值或者引用。

public void noChangeParam(final Refe ref,final int a) {
		//不能修改
		//a = 3;
		//ref = new Refe(22);
}

 

 

final方法

final修饰方法时包含的语义是:该方法禁止重写。注意,可以重载。

有一点值得我们特别注意:类中所有的private方法都隐式的指定为final,也就是子类中无法覆盖它。其实这也很好理解,private不具有子类继承性,所以子类也就不存在覆盖它的可能。但是如果对private方法显示的添加final修饰词(虽然这没有任何意义),但是这可能会造成混淆。

class WithFinals {
	
	private final void f() {
		System.out.println("WithFinal.f()");
	}
	
	private void g() {
		System.out.println("WithFinal.g()");
	}
}
/*
 * 看起来子类好像覆盖了父类的private方法和private final方法
 */
class OverridingPrivate extends WithFinals {

	private final void f() {
		System.out.println("OverridingPrivate.f()");
	}
	
	private void g() {
		System.out.println("OverridingPrivate.g()");
	}
}

 

 

看起来子类覆盖了父类中的private final方法,这怎么可能呢?!这又该如何解释呢?

我们一定要正确理解覆盖的意思,“覆盖”只有在某个方法是父类接口的一部分时才会出现,也就是说这个方法必须是子类可以看见的,这样子类向上转型为父类时,可以通过调用这个方法。但是当方法是private时,它就不是父类接口的一部分,它只是父类私有的,子类看不见。这个时候子类完全可以生成一个具有同样签名的方法,它也仅仅是恰巧有着同样的方法签名而已,并不是覆盖。

 

final

final类无法继承,final类中的方法也就不存在覆盖的问题了,所以final类中的所有方法都隐式的指定为final

 

以上内容来自于对《Thinkin Java》这本书中关于final的理解,关于final方法,其中提到了在Java5以前实用final修饰方法是为了提高效率,同意编译期将该方法的所有调用都转为内嵌调用。但是虚拟机现在做了很多优化,效率已经不成问题,所以实用final修饰方法的唯一理由就是:明确禁止覆盖。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值