final修饰符:
类变量:1.在声明该变量时指定初始值。2.在静态初始块中指定初始值。只能在这两个地方其中之一指定。
实例变量:1.声明该实例变量时指定初始值。2.在非静态初始化块中指定初始值。3.在构造函数中指定初始值。必须在这三个地方指定初始值。
只能在初始化块或静态初始化块赋值,不能再初始化块或静态初始化块中声明,因为在初始化块或静态初始化块中声明相当于局部变量。
都不能在普通方法中为final修饰的成员变量赋值。
final 修饰的成员变量必须显式的指定初始值,系统不会对final成员进行隐式的初始化。
不能对final修饰的形参重新赋值
final修饰的基本类型变量,不能对基本类型变量重新赋值。但是final修饰的引用类型变量。它保存的知识一个引用,final只保证这个引用类型变量所引起的地址不会改变,即一直指向同一个对象,但这个对象可以发生改变。
final修饰的引用类型变量不能够重新赋值,但是可以改变这个引用类型变量所指的对象的内容。
宏替换
对一个final变量来说,不管是类变量还是实例变量还是局部变量,只要改变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。
1. 使用final修饰符修饰。
2. 在定义该final变量时指定了初始值。
3. 该初始值在编译时就确定下来。
package learnJava;
import java.util.Arrays;
public class FinalTest {
public int age;
final static int q=61;
final static String dstr;
final float er;
final String str12;
{
final int a=12;//同样是final局部变量,不能通过对象访问。
str12="ljkkj";
System.out.println("初始化块"+a);
}
static {
final double w4=3.3;//这里的w4是局部final变量,
System.out.println("静态初始化块"+w4);
dstr="jiki";
// final static int h=12;//不能够在static块中定义类变量
}
public FinalTest(int age) {
this.age=age;
er=2.2f;
System.out.println("构造函数"+er);
}
public void test(final int a)
{
//a=2;
//错误,不能对final修饰的形参进行赋值
}
public static void main(String[] args) {
FinalTest dsd=new FinalTest(12);
// System.out.println(dsd.a); 出错
// System.out.println(dsd.w4); 出错
System.out.println(dsd.str12);
System.out.println(FinalTest.dstr);
System.out.println("-----final基本类型变量和引用类型变量------");
final int[] arr= {12,23,4,45};
System.out.println(Arrays.toString(arr));//12 23 4 45
arr[0]=11;
System.out.println(Arrays.toString(arr));//11 23 4 45
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//4 11 23 45
//arr=null;
//arr= {1,23};都是非法的不能重新赋值。
final FinalTest ft=new FinalTest(100);//是因为新对象会执行
System.out.println(ft.age);
ft.age=101;
System.out.println(ft.age);
//ft=null;非法
System.out.println("-----可执行宏替换的final变量----");
String s1="hello";
final String s1_="hello";
String s2="world";
final String s2_="world";
String s3="helloworld";
String s4=s1+s2;
String s4_=s1_+s2_;
System.out.println(s3==s4);//false
System.out.println(s3==s4_);//true
//因为s4还是引用不是常量,不能够在编译时就确定下来,而s1、s2、s3都是常量在编译就直接确定下来,在常量池中。
//要解决这个问题可以直接将s1与s2进行宏替换,即加上final,这样s4在编译就能够确定。
//宏替换必须在声明该变量的时候加上final赋初值
}
}
输出结果:
静态初始化块3.3
初始化块12
构造函数2.2
ljkkj
jiki
-----final基本类型变量和引用类型变量------
[12, 23, 4, 45]
[11, 23, 4, 45]
[4, 11, 23, 45]
初始化块12
构造函数2.2
100
101
-----可执行宏替换的final变量----
false
true
final方法
final修饰的方法不可以被重写,不希望子类重写父类的方法。(如getClass()方法)
对于private final 修饰的方法,因为它仅在当前类中出现,子类无法访问该方法,因此在子类中定义了一个和父类相同名、相同返回类型、相同形参列表的方方法,依然编译成果,因为子类不是重写了父类的privat final方法,只是重新定义了一个方法。
final方法不能够被子类重写,但是可以添加形参重载。
public class FianlMethod {
public final void test() {}
private final void train() {}
public final void test(String arg) {}//编译成功
}
class Sub extends FianlMethod{
//public void test() {} 编译错误
public void train() {} //编译成功
}
final类
final修饰的类不可以有子类,如java.lang.Math类就是一个final类,它不可以有子类。