Java中的关键字final

Java中的关键字final

一、final的基础使用

1. 修饰类:

  • 当某个类的整体被final修饰时,说明该类无法继承,且此类不能有子类。
  • 注意:final类中所有方法都隐式为final,因无法覆盖他们,所以在final类中给任何方法添加final关键字无任何意义。

设计模式中最为重要的两种关系,一种是继续/实现;另一种是组合关系。当遇到不能用继承的(final修饰类),应考虑用组合。代码入下:

class Mystring{
	private string innerString;
	//支持老的方法
	public int length(){
		return innerString.length();//通过innerString调用老的方法
	}
	//添加新的方法
	public String toMyString(){
		//...
	}
}

2. 修饰方法:

  • private 方法是隐式方的final
  • final 方法是可以被重载的

private fina
类中所有private 方法都隐式地指定为final的,由于无法取用private方法,所以也就不能覆盖它。可以对private方法增添final关键字,但并没什么好处。如下例子:

public class Base{
	private void test(){}
}

public class Son extends Base{
	public void test(){}
	public static void main(String[] args){
		Son son = new Son();
		Base father = son;
		//father.test();
	}
}

Base和Son都有方法test(),但是这并不是覆盖,private所修饰的方法是隐式的final,也就是无法被继承,所以更不能说覆盖,在Son中的test()方法属于Son的新成员,Son进行向上转型得到father,但是father.test()是不可以执行的。因Base中的test方法是private的,无法访问。

final方法是可以被重载的

public class FinalExampleParent{
	public final void test(){
	}
	public final void test(String str){
	}
}

3. 修饰参数:

  • Java允许在参数列表中以声明的方式将参数指定为final,这就表示你方法在方法中更改参数引用所指向的对象。这种特性主要用来向匿名内部类传递数据。

4. 修饰变量:
编译期常量和非编译期常量

public class Test{
	//编译期常量
	final int i = 1;
	final static int j = 1;
	final int[] a = {1,2,3};
	//非编译期常量
	Random r = new Random();
	final int k = r.nextInt();
	
	public static void main(String[] args){
	} 
}

k的值是有随机数对象决定,所以不是所有的final修饰的字段都是编译期常量,只是k的值在被初始化后无法更改。

static final
一个既是static又是final的字段只占据一段不能修改额存储空间,它必须在定义的时候进行赋值,否则编译器不给予通过。

import java.util.Random

public class Test{
	static Random r = new Random();
	final int a = r.nextInt(10)+1;
	static final int b = r.static nextInt(10)+1;
	public static void main(String[] args){
		Test t1 = new Test();
		System.out.println("a = "+ t1.a + " b = "+ t1.b)
		Test t2 = new Test();
		System.out.println("a = "+ t2.a + " b = "+ t2.b)
	}
}

上述代码结果为:

a = 2  b = 7
a = 8  b = 7

运算结果:a 不相同,b 相同的原因:
static 关键字所修饰是字段并不是对象,而是属于这个类,也就是是static final 所修饰的字段仅占据内存的一个一份空间,一但被初始化之后便不会被更变。

blank final
Java允许生成空白final,也就是说被声明为final但又没有给出定值的字段,但是在该字段被使用之前被赋值

  • 在定义处进行赋值(这不叫空白final)
  • 在构造器中进行赋值,保证该值在被使用前赋值

这增强了final的灵活性。

public class Test{
	final int a = 1;
	final int b;//空白final
	public Test(){
		b = 2;
		}
		public Test(int x){
			this.b = x;
		}
}

上面代码可以看出b的赋值更为灵活,但请注意,如果字段由static和final修饰,仅能在定义处赋值,因该字段不属于对象,属于这个类。

二、使用final的限制条件和局限性

  • 当声明一个final成员时,必须在构造函数退出前设置它的值
public class MyClass{
	private final int a = 1;
	public MyClass(){
		...
	}
}

或者

public class MyClass{
	private final int a;
	public MyClass(){
		...
		a = 1;
		...
	}
}
  • 将指向对象的成员声明为 final 只能将该引用设为不可变的,而非所指的对象。

下面的方法仍然可以修改该 list。

private final List list= new ArrayList();
list.add("Hello");

声明为 final 可以保证如下操作不合法

list = new ArrayList();
list= someOtherList;
  • 如果一个对象将会在多个线程中访问并且你并没有将其成员声明为 final,则必须提供其他方式保证线程安全。

  • " 其他方式 " 可以包括声明成员为 volatile,使用 synchronized 或者显式 Lock 控制所有该成员的访问。

final关键字的总结:

final 可以声明类、成员变量、方法、以及本地变量:

  1. 不允许被继承的类,如:String类。
  2. 不允许修改引用的域对象。
  3. 不允许被覆写的方法,如:POJO类的setter方法。
  4. 不允许运行过程中重新赋值的局部变量。
  5. 避免上下文重复使用一个变量,使用final可以强制重新定义一个变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值