final关键字
1 final修饰的类无法继承。
2 final修饰的方法无法覆盖。
3 final修饰的变量只能赋值一次值。
4 final修饰的引用一旦指向某个对象,则不能在重新指向其他对象,但该引用指向的对象内部的数据是可以修改的。
5 final修饰的实例变量必须手动初始化,不能采用系统默认值。
6 final修饰的实例变量一般和static联合使用,称为常量。
public static final double PI = 3.1415926;
案例1:
/* * final * 1 final是java语言中的一个关键字。 * 2 final表示最终的,不可变得。 * 3 《重点》final修饰的变量? * final修饰的局部变量,一旦赋值,不能重新赋值。 * * 4 《重点》final修饰的方法? * final修饰的方法无法被覆盖,被重写。 * * 5 《重点》final修饰的类? * final修饰的类无法被继承 * * 6 《提示》final控制不了能不能调用的问题。final管的是啥? * final修饰的表示最后的。不能变的,不能改的。 * * 重点【精辟:final修饰的变量,只能赋一次值。】 * */ public class FinalTest01 { public static void main(String[] args) { D d = new D(); d.doSome(); // 局部变量 int i =100; // 重新赋值 i = 200; // 局部变量 final int k = 100; // 重新赋值 // Error:(28, 9) java: 无法为最终变量k分配值 // k = 300; // 初始化这个m final int m; // 重新赋值 m = 200; // 二次赋值 // Error:(38, 9) java: 可能已分配变量m // m = 300; } } final class A{ // A没有子孙 } // B类继承A类,相当于对A类的功能进行扩展。如果你不希望别人对A类型进行扩展。 // 你可以给A类加一个final关键字,这样的话A类就无法继承了。 // 错误:无法从最终A进行继承 /*class B extends A{ }*/ // Error:(26, 24) java: 无法从最终java.lang.String进行继承 /*class MyString extends String{ }*/ class C{ public final void doSome(){ System.out.println("C's doSome..."); } } /*Error:(39, 17) java: D中的doSome()无法覆盖C中的doSome() 被覆盖的方法为final*/ class D extends C{ /*public void doSome(){ System.out.println("D's doSome..."); }*/ }
内存图:
案例2:
/* * final修饰的变量,如果这个变量是一个“引用”会怎样??? * 《重点》final修饰的变量只能赋一次值。(万变不离其宗) * “引用”是不是一个变量呢????是 * * final修饰的引用: * 该引用只能指向1个对象,并且他只能永远指向该对象。无法在指向其他对象。 * 并且在该方法在执行过程中,该引用指向该对象之后,该对象不会被垃圾回收器回收。 * 直到当前方法结束,才会释放空间。 * * 虽然final的引用指向对象A后,不能在重新指向对象B * 但是对象A内部的数据可以被修改。 * */ public class FinalTest02 { public static void main(String[] args) { Person person = new Person(30); System.out.println(person.age); //-------------------------------------- // 代码不管怎么变化,p也是一个变量。(只不过这里他有一个特殊的名字:引用) final Person p = new Person(30); //Error:(9, 9) java: 无法为最终变量p分配值 //p = new Person(30); //Error:(20, 9) java: 无法为最终变量p分配值 //p = null; /*final int i = 10; // 这是不允许的 i = 20;*/ p.age = 40; System.out.println(p.age); } } class Person{ int age; public Person() { } public Person(int age) { this.age = age; } }
案例3:
/* * final修饰的实例变量呢? * 《重点:万变不离其宗》:final修饰的变量只能赋一次值。(这句话到哪里都好用) * * 你是否还记得:实例变量如果没有手动赋值的话,系统会默认赋值。 * * java程序设计:不背锅!!!甩锅甩的很好!!! * * 实例变量在什么时候赋值(初始化)? * 构造方法执行的过程中赋值。(new的时候赋值) * * 终极结论: * final修饰的实例变量,系统不管赋默认值,要求程序员必须手动赋值。 * 这个手动赋值,在变量后面赋值可以,在构造方法中赋值也可以。 * */ public class FinalTest03 { public static void main(String[] args) { //创建对象必须调用无参构造方法吗? //不一定 User user = new User(100); User user1 = new User(200); } } class User{ // 实例变量 // Error:(15, 15) java: 变量 age 未在默认构造器中初始化 //final int age; // 实例变量 int age; // 实例变量 // 这样可以,因为程序员手动赋值了 final double height = 1.8; // 以下这一堆代码全部联合起来,weigth变量也是赋值1次。 // 实例变量 final double weight; /*public User() { System.out.println("Hello World!"); // 如果不这样写的话,那么系统在运行的时候会默认执行无参构造方法,那么他就赋默认值,这样是不行的。 this.weight = 80;// 只要我赶在系统赋默认值之前赋值就行。 // 如果你不写上面的代码,系统赋默认值是在这个时候 // 那你给他赋默认值了,那就不可以进行修改了,那sun公司的java工程师不背锅,人家不允许你赋默认值。 所以就报错了。 // weight = 0; //Error:(44, 13) java: 可能已分配变量weight //this.weight = 88; }*/ // 这样跟上面是一样的 public User(double weight) { // 这也是赋值了,没有采用系统默认值。他也是系统默认赋值一次。 this.weight = weight; } }
案例4:
/* * * 上一个例子的结论: * final修饰的实例变量,必须手动赋值。 * 《重点》final修饰的变量,只能赋一次值。 * * final修饰的变量一般添加static进行修饰。 * 终极结论: * static final修饰的变量称为“常量”。 * 常量名建议全部大写。每个单词之间用下划线进行衔接 * * 常量:实际上常量和静态变量一样,区别在于: * 常量的值不能变。 * 常量和静态变量,都是存储在方法区,并且都是在类加载时初始化。 * * 常量一般都是公共的:public的,因为你改不了。 * */ public class FinalTest04 { public static void main(String[] args) { System.out.println(Chinese.COUNTRY); //Error:(20, 16) java: 无法为最终变量COUNTRY分配值 //Chinese.COUNTRY = "美国"; System.out.println(MyMath.PI); } } class Chinese{ // 身份证号 每个人都不一样 对象级别的 String idCard; // 姓名,对象不同姓名不同。 String name; // 国家的值是一个固定的值,中国 // 实例变量在堆中,一个对象一份,一百个对象一百份。 // 实例变量既然使用final修饰了,说明该实例变量值不会随着对象的变化而变化。 // 该实例变量前面应该添加:static关键字,变为静态的,存储在方法区。 // static final String country = "中国"; static final String COUNTRY = "中国"; // i永远都是10,创建100个对象,i也是10 // i是10永远都不会发生改变的,既然这样,没必要声明为实例变量,最好是静态的,节省内存空间。 static final int I = 10; } class MyMath{ // 数学中的π是永远不会变的 public static final double PI = 3.141592627; }