final 可以定义在接口、类、方法、变量上,根据定义的位置不同,作用也不尽相同。
当final作用在接口上
在接口中定义的信息即为公共,即所以实现接口的类都具有相同的属性。对应外部调用时,返回的效果也应该是一致的。
所以,在接口上定义的变量值,默认类型就是public static final的,它不允许实现类擅自修改变量的值。
public interface Hello{
//接口定义变量时,默认类型就是
//public static final
String name = "Amkio" ;
}
public static void main(String[] args) {
System.out.println("Hello " + Hello.name);
}
当实现类尝试修改接口上的变量值时,编译器给出了错误提示
Multiple markers at this line
- The final field Hello.name cannot be assigned
- The static field Hello.name should be accessed in a
static way
public class HelloWorld {
//这里在编译器中会报错
public void setName(String name) {
this.name = name ;
}
public interface Hello{
String name = "Amkio" ;
}
当final作用在Class上
在类定义上添加final关键字后,即表示不允许有子类出现!!(断子绝孙了~~~~~)
The type HelloJava cannot subclass the final class HelloWorld
public final class HelloWorld {
private String name = null ;
public void setNameA(String name) {
this.name = name ;
}
}
//这里在编译器中会报错
class HelloJava extends HelloWorld{}
当final作用在方法上
在方法的返回类型前添加上final,即表示该方法在子类中不允许修改。
public class HelloWorld {
public String name = null ;
public final void setNameA(String name) {
this.name = name ;
}
}
class HelloJava extends HelloWorld{
//这里在编译器中会报错,因为父类中该方法已经设置为final,即表示不允许子类修改。
public void setNameA(String name) {
this.name = "AAAA" ;
}
}
当final作用在变量上
即常量,这一种是我们最常使用的,此处省略几百字。。。。。。。
public final class HelloWorld {
private String name = null ;
public static void main(String[] args){
System.out.println(HelloWorld.name);
}
}
final常量的初始化
常量变量只能初始化一次,但是。。。。却有两种方法:
1. 一般是在定义变量的时候即赋值。参考 public final int A=0
2. 如果有特殊要求,例如:来自配置文件、来自入参、需要计划等,可以通过构造器来完成初始化
public class HelloWorld {
public final int A = 0;
public final int B ;
public HelloWorld() {
B = 2 ;
}
}
final静态常量的初始化
静态常量也是常量,所以也只能初始化一次,但是。。。。也有两种方法:
1. 一般是在定义变量的时候即赋值。参考 public static final int B=0
2. 如果有特殊要求,例如:来自配置文件、来自入参、需要计划等,可以通过静态块完成。
public class HelloWorld {
public static final int A ;
public static final int B =0;
static { //静态块
A = 1 ;
}
}
当final作用在参数上
在一个方法的入参上添加final关键字,表示该参数的数值不允许在方法内被改变。对于大多数的场景下,此做法没有什么必要的用处,因为在java的传参过程中,大多数都传的是只是值。所以,不会影响调用者的值发生改变。
public class HelloWorld {
public String name = null ;
public void setNameA(final String name) {
this.name = name ;
//这里在编译器中会报错
//The final local variable name cannot be assigned. It must be blank and not using a compound assignment
name = "abc" ;
}
}
接下来,有个奇怪的事情发生了,我写了这样一段代码,但是结果却超出了我的预期~~~~~~~
public class HelloWorld{
public String name = null ;
public void setName(final char[] name) {
this.name = String.valueOf(name) ;
name[0] = '2' ; //这里没报错~~~~~
}
public static void main(String[] args) {
HelloWorld hello = new HelloWorld();
char[] c = {'A','m','k','i','o'} ;
hello.setName(c);
System.out.println(String.valueOf(c));
}
}
输出结果:
1mkio
2mkio
因为这里的name指的是实参的地址的拷贝,你可以通过它修改这个地址的内容,因为此时这个内容的地址和原地址是同一地址,但是地址本身没有发生改变。
如果将上面的name[0] = '2' ; 改成 char[] ab= {'a','b'}; name = ab ; 会怎么样呢??
"The final local variable name cannot be assigned. It must be blank and not using a compound assignment"
"remove 'final' modifier of 'name'"
完!!