【Java】final关键字

你真的了解final关键字了么?

许多编程语言都有某种方法来告诉编译器有一块数据是恒定不变的,Java中就是通过final关键字来实现;

1、一个永不改变的编译时常量
2、一个在运行时被初始化的值,而你不希望他被改变

也就是说这个恒定不变的数值不一定一定得是在编译时就定死了的,也有可能是在运行时期生成的,一个static 又是 final的域只占据一段不能改变的存储空间

对于基本数据类型来说,final表示的是他的数值是恒定不变的,但是如果是一个对象引用,final时引用恒定不变,但是对象自身是可以有变化的。

空白final

就是说在被声明为final但又未给定初值的域。无论有什么情况,编译器都确保空白final在使用前会被初始化,但是空白final在关键字final的使用上提供了更大的灵活性

必须在域的定义出或者每个构造器中用表达式对final进行赋值,也保证了final域在使用前总是被初始化

package finaltest;

public class Poppet {
	private int i;
	
	Poppet (int ii){
		i = ii;
	}
}
//-----------------------------------------------------------
package finaltest;

public class BlankFinal {
	private final int i = 0;
	private final int j;
	private final Poppet p;
	
	public BlankFinal() {
		j = 1;
		p = new Poppet(1);
	}
	
}

final参数

在刚学Android的时候,经常写方法的时候代码被标红,然后AndroidStudio中alt + Enter帮助更改代码,经常会在这个方法的参数列表里给他加一个final关键字;

Java中是允许以声明的方式将参数指明为final的。表示没办法在方法中更改参数引用所指向的对象

final方法

1、把方法锁定,防止任何继承类修改他的含义。
2、确保继承中是方法保持不变,不会被覆盖。

final和private:
所有的private方法其实也就是指定成了final。因为没办法取用private方法,所以更不用谈覆盖了。当然如果你继承了一个类,并且写了一个方法,跟父类的final修饰的方法是一样的,即按照方法重写的样子去实现,编译会成功并在执行的时候看起来也是预期的结果,但是实际上并不是方法重写,而仅是生成了一个新的方法

“覆盖”只是在某方法是积累的接口的一比分才会出现,必须能将一个对象向上转型为它的基类,并调用相同的方法。如果某一个方法是private,那么他就不是基类的接口的一部分。他是一些隐藏于类中的程序代码,只不过是具有相同的名称而已;

package extend;

public class Base {
	private int date1;
	private int date2;
	public int date3;
	public int getDate1() {
		return date1;
	}
	public void setDate1(int date1) {
		this.date1 = date1;
	}
	public int getDate2() {
		return date2;
	}
	public void setDate2(int date2) {
		this.date2 = date2;
	}
	public int getDate3() {
		return date3;
	}
	public void setDate3(int date3) {
		this.date3 = date3;
	}
	
	public final void base() {
		System.out.println("this is base");
	}
}

在这里插入图片描述

final类

将某个类定义成final时,就是说不可以在继承这个类,不希望他拥有子类;
final类是禁止继承的,所以final类中所有的方法其实也是final的,因为肯定没办法覆盖他们。

初始化及类的加载

每个类的编译代码都存在于他自己的独立文件中,这个文件只在需要使用程序代码的时候才会被加载。可以说“类的代码在初次使用时才加载”。通常是发生在new第一个对象的时候或者是访问他的static变量/方法的时候;

继承和初始化

package extend;

public class Insect {
	private int i = 9;
	protected int j;
	Insect(){
		System.out.println("i = " + i + " j = " + j);
		j = 39;
	}
	
	private static int x1 = printInit("static Insect.x1 initialized");
	
	static int printInit(String s) {
		System.out.println(s);
		return 47;
	}
}
//-------------------------------------------------------

package extend;

public class Beetle extends Insect {
	private int k = printInit("Beetle.k initialized");
	
	public Beetle() {
		System.out.println("k = " + k);
		System.out.println("j = " + j);
	}
	
	private static int x2 = printInit("static Beetle.x2 initialized");
	
	public static void main(String[] args) {
		System.out.println("Beetle constructor");
		Beetle b = new Beetle();
	}
}

//------------------------------------------
//output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9 j = 0
Beetle.k initialized
k = 47
j = 39

反正我刚开始的时候很懵逼,这执行main方法第一句就是打印,但是为什么前面多了两行打印呢。因为忽略了类的加载和初始化过程;

当运行的时候,发生的第一件事就是试图访问Beetle里面的main()方法,这个方法是static修饰的,所以类加载器就会开始找出Beetle.class文件。在对它加载的时候,发现它有一个基类,那又要对他进行加载,不管是不是打算产生一个基类的独享,这一步都是会进行的;

这时候基类中的static要初始化,所以就出现了前面有两行打印的情况!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值