final说明
- 修饰类:表示类不可被继承
- 修饰方法:表示方法不可被子类覆盖,但是可以重载
- 修饰变量:表示变量一旦被赋值就不可以更改它的值
-
修饰成员变量
- 如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。
- 如果final修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中执行初始值。
-
修饰局部变量
系统不会为局部变量进行初始化,局部变量必须显示初始化。因此使用final修饰局部变量时,即可在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初始值(仅一次)
package com.dameng; /** * @author Allen */ public class FinalVar { /** * 声明时就要赋值,或者在静态代码块中赋值 */ private final static int A = 0; // static { // A = 1; // } /** * 声明时、代码块或者构造函数赋值 */ private final int b = 0; // { // b = 1; // } // public FinalVar() { // b = 2; // } public static void main(String[] args) { // 局部变量只声明不初始化,不会报错 final int localA; // 在使用之前一定要赋值 localA = 0; // 报错,不允许修改 // localA = 1; } }
-
修饰基本类型数据和引用类型数据
- 如果是基本类型的变量,则其数值一旦在初始化之后便不能更改;
- 如果是引用类型的变量,则初始化之后不能再指向另一个对象,但引用值可以修改。
package com.dameng; /** * @author Allen */ public class FinalReferenceTest { public static void main(String[] args) { final int[] arr = {1, 2, 3, 4}; arr[2] = 3; // 报错,不能对arr重新赋值 // arr = null; final Person person = new Person(); person.setAge(24); // 报错,不能对arr重新赋值 // person = null; } private static class Person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } }
为什么局部内部类和匿名内部类只能访问局部final变量(<=jdk7)?
匿名内部类
package com.dameng;
/**
* 编译之后会生成两个class文件,Test.class Test$1.class
*
* @author Allen
*/
public class Test {
public static void main(String[] args) {
}
public void test(final int b) {
final int a = 10;
new Thread() {
@Override
public void run() {
System.out.println(a);
System.out.println(b);
}
}.start();
}
}
package com.dameng;
public class Test {
public Test() {
}
public static void main(String[] args) {
}
public void test(final int b) {
int a = true;
(new Thread() {
public void run() {
System.out.println(10);
System.out.println(b);
}
}).start();
}
}
package com.dameng;
class Test$1 extends Thread {
Test$1(Test this$0, int var2) {
this.this$0 = this$0;
this.val$b = var2;
}
public void run() {
System.out.println(10);
System.out.println(this.val$b);
}
}
局部内部类
package com.dameng;
/**
* 编译之后生成两个class文件,Test.class Test$1InClass.class
*
* @author Allen
*/
public class Test {
private int age = 12;
public static void main(String[] args) {
}
public void outPrint(final int x) {
class InClass {
public void inPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().inPrint();
}
}
package com.dameng;
public class Test {
private int age = 12;
public Test() {
}
public static void main(String[] args) {
}
public void outPrint(final int x) {
class InClass {
InClass() {
}
public void inPrint() {
System.out.println(x);
System.out.println(Test.this.age);
}
}
(new InClass()).inPrint();
}
}
package com.dameng;
class Test$1InClass {
Test$1InClass(Test this$0, int var2) {
this.this$0 = this$0;
this.val$x = var2;
}
public void inPrint() {
System.out.println(this.val$x);
System.out.println(this.this$0.age);
}
}
jdk8以后匿名内部类可以直接访问局部变量
匿名内部类
package com.dameng;/** * 编译之后只生成一个class文件,Test.class * * @author Allen */public class Test { public static void main(String[] args) { } // final可有可无 public void test(final int b) { // final可有可无 final int a = 10; new Thread(() -> { System.out.println(a); System.out.println(b); }).start(); }}
package com.dameng;public class Test { public Test() { } public static void main(String[] args) { } public void test(int b) { int a = true; (new Thread(() -> { System.out.println(10); System.out.println(b); })).start(); }}
局部内部类
package com.dameng;/** * 编译之后生成两个class文件,Test.class Test$1InClass.class * * @author Allen */public class Test { private int age = 12; public static void main(String[] args) { } // final可有可无 public void outPrint(final int x) { class InClass { public void inPrint() { System.out.println(x); System.out.println(age); } } new InClass().inPrint(); }}
package com.dameng;public class Test { private int age = 12; public Test() { } public static void main(String[] args) { } public void outPrint(final int x) { class InClass { InClass() { } public void inPrint() { System.out.println(x); System.out.println(Test.this.age); } } (new InClass()).inPrint(); }}
package com.dameng;class Test$1InClass { Test$1InClass(Test this$0, int var2) { this.this$0 = this$0; this.val$x = var2; } public void inPrint() { System.out.println(this.val$x); System.out.println(this.this$0.age); }}