一、fianl

1、final数据

Final可以修饰静态变量,实例变量和局部变量。
final修饰一个永不改变的编译时常量或者是一个运行时被初始化的值,而你不希望他被改变。
对于基本数据类型final使其数值恒定不变,对于对象引用final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。(对象自身是可以被修改的)
必须在域的定义处或者每个构造器中用表达式对final进行赋值。
空白final:
final变量定义的时候,可以先声明,而不给初值,称为空白final。编译器确保空白final在使用之前必须被初始化。一个类中的final数据成员可以实现依对象而有所不同,却有保持其恒定不变的特征。(绕晕了,来看看代码清醒一下吧)
代码演示:

class Poppet{
	private int i;
	Poppet(int ii){
		ii=i;
	}
}
public class BlankFinal {
private final int i=0;//初始化final
private final int j;//空白final
private final Poppet p;
public BlankFinal(){
	j=1;
	p=new Poppet(1);
	System.out.println("j="+j);
}
public BlankFinal(int x){
	j=x;
	p=new Poppet(x);
	System.out.println("j="+j);
}
	public static void main (String args[]){
		new BlankFinal();
		new BlankFinal(47);	
	}
}

运行结果:
j=1
j=47

Final参数:
Java允许在参数列表中以声明的方式将参数指明为final,这意味着无法在方法中更改参数引用所指向的对象。
当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
代码演示:

class Gizmo{
	public void spin(){System.out.println("可以在方法中改变无final修饰的参数引用所指对象");}
}
public class FinalArguments {
void with (final Gizmo g){
	//g=new Gizmo();不能在方法中更改final参数引用所指向的对象
	System.out.println("不能在方法中更改final参数引用所指向的对象");
}
void without(Gizmo g){
	g=new Gizmo();
	g.spin();
}
//void f(final int i){i++;}不能改变final参数的值
int g(final int i){
	return i+1;//这里仅仅是返回了i+1,i的值本身没有变
}
	public static void main(String[] args) {
		FinalArguments bf=new FinalArguments();
		bf.without(null);
		bf.with(null);
	}
}

运行结果:
可以在方法中改变无final修饰的参数引用所指对象
不能在方法中更改final参数引用所指向的对象

2、final方法

Final不能用于修饰构造方法。
使用final方法的原因:
一是锁定方法,防止任何继承类修改。
二是效率。
final和private关键词:
类中所有的private方法都隐式的指定为final,其他类因为无法取用private方法,所以就无法覆盖它,所以对private方法加final修饰词没有意义。
代码演示:

class WithFinals{
	private final void f(){
		System.out.println("WithFinals.f()");
	}
	private void g(){
		System.out.println("WithFinals.g()");
	}
}
class OverridingPrivate extends WithFinals{
	private final void f(){
		System.out.println("OverridingPrivate.f()");
	}
	private void g(){
		System.out.println("OverridingPrivate.g()");
	}
}
class OverridingPrivate2 extends OverridingPrivate{
	public final void f(){//并没有覆盖父类方法,只是名字相同而已
		System.out.println("OverridingPrivate2.f()");
	}
	public void g(){//并没有覆盖父类方法,只是名字相同而已
		System.out.println("OverridingPrivate2.g()");
	}
}
public class FinalOverridingIllusion {
	public static void main(String[] args) {
		OverridingPrivate2 op2=new OverridingPrivate2();
		op2.f();
		op2.g();
		OverridingPrivate op=op2;
		//op.f();
		//op.g();
		WithFinals wf=op2;
		//wf.f();
		//wf.g();
	}
}

运行结果:
OverridingPrivate2.f()
OverridingPrivate2.g()
覆盖只能是某方法是基类的接口的一部分时才会出现,即,必须能将一个对象向上转型为它的基本类型并调用相同的方法,如果某方法为private,他就不是基类的接口的一部分。

3、final类

不能被继承,final类中的所有方法都隐式指定为是final的

二、Static

被static修饰的成员变量和成员方法独立于该类的任何对象,可以直接通过类名访问或者调用,它不依赖类特定的实例,被类的所有实例共享。(有点儿全局变量,全局方法的意思)

1、static变量

成员变量分为两种:
一种是被static修饰的变量,叫做静态变量。
另一种是没有被static修饰的变量,叫做实例变量。
由于静态变量独立于该类的任何对象,它只被初始化一次分配一次内存,而实例变量是每new一次初始化一次,分配一次内存。

2、static方法

静态方法中不能用this和super关键字,构造方法不能被static修饰,不能直接访问所属类的实例变量和实例方法,只能访问所属类的静态成员变量和成员方法。因为static方法独立于任何实例,所以static方法必须被实现,而不能是抽象的abstract。

3、static块

在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,每个代码块只会被执行一次。

三、既是static又是final的域

static final用来修饰的域只占据一段不能改变的存储空间。 对于变量,表示一旦给值就不可修改,对于方法,表示不可覆盖,并且都可以通过类名直接访问。
既是static又是final的域全部用大写表示,并使用下划线分割各个单词:
代码演示:

class Value{
	int i;
	public Value(int i){
		this.i=i;
	}
}
public class FinalData {
 static Random rand=new Random(47);
 final int valueOne=rand.nextInt(20);//虽然为final值,但是对象不同,值就不同
 static final int VALUE_TWO=rand.nextInt(20);//static初始化一次,final值不因对象的变化变化
 static final int VALUE_THREE=39;
private Value v1=new Value(11);
private final Value v2=new Value(22);
private static final Value VAL_3=new Value(33);
private final int a []={1,2,3,4,5,6};
String id;
FinalData(String id){this.id=id;}
public String toString(){
	return id+":"+"valueOne="+valueOne+",VALUE_TWO="+VALUE_TWO+",VALUE_THREE="+VALUE_THREE;
}
	public static void main(String[] args) {
		FinalData fd1=new FinalData("fd1");
		//fd1.valueOne++;final修饰的值不能改变
		fd1.v2.i++;//v2是final引用,它所指的对象的值是可以改变的
		fd1.v1=new Value(9);
		//fd1.v2=new Value(0);final引用不能改变引用所指的对象
		//fd1.VAL_3=new Value(1);final引用不能改变引用所指的对象
		//fd.a=new int[3];final引用不能改变引用所指的对象
		for(int i=0;i<fd1.a.length;i++)
			fd1.a[i]++;//final引用不变,但是它指向的对象的值在改变
		System.out.print("a[]= ");
		for(int t:fd1.a)
		System.out.print(t+" ");
		System.out.println();
		System.out.println("Creating new FinalData");
		FinalData fd2=new FinalData("fd2");
		FinalData fd3=new FinalData("fd3");
	    System.out.println(fd1);
	    System.out.println(fd2);
	    System.out.println(fd3);
	}
}

运行结果:

a[]= 2 3 4 5 6 7

Creating new FinalData

fd1:valueOne=15,VALUE_TWO=18,VALUE_THREE=39

fd2:valueOne=13,VALUE_TWO=18,VALUE_THREE=39

fd3:valueOne=1,VALUE_TWO=18,VALUE_THREE=39