final 在 java 中有什么作用?
一般有五种用法
final修饰类
格式:
public final class 类名称{ //.. }
限制:
- 被修饰的类不能有任何子类
- 也就意味着所有方法都不能被重写
- 类中不能有抽象方法或者不能与抽象类并存
注意:一个类是final的,那么所有成员方法都无法进行覆盖重写,final类中的成员变量可以根据需要设置成final,但是final类下的所有方法都会隐式的指定为final方法,在使用final修饰类的的时候,一定要慎重选择,除非这个类以后不会用来继承或者出于安全考虑,尽量不要将类设计成final类
final修饰方法
格式:
修饰符 final 返回值类型 方法名称(){ ..... }
- 当final用来修饰一个方法的时候,这个方法就是最终方法,那么很明显就是说不能被覆盖重写
使用final修饰方法的原因:1.把方法锁死,防止任何继承类修改他的含义。2.效率。在早期的Java实现版本中,会将final方法转为内嵌调用。如果方法过于庞大,可能看不到内嵌调用的带来的任何性能提升。在最近的java版本中,不需要用final方法进行这些优化。
此外还要注意一点:因为重写的前提是子类可以从父类中继承此方法,如果父类方法中final修饰的方法同时访问的权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同名字和参数的方法。此时不在产生重写的与final的矛盾,而在子类中重新定义新的方法。(注:类的private方法会隐式的指定final方法)
final修饰变量
格式:
final 变量类型 变量名称=变量值
限制:
- 基本数据类型:第一次赋值后面就不能改变了。
- 引用数据类型:第一次被赋值(对象的地址值),该引用的地址值将无法改变。
final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常由final定义的变量称为常量,常量名一般推荐使用大写字母表示,如果变量名有多个部分使用下划线"_"分隔。
final修饰参数
在实际应用中,我们除了可以用final修饰成员变量、成员方法、类,还可以修饰参数、若某个参数被final修饰了,则代表了该参数是不可改变的。如果在方法中我们修改了该参数,则编译器会提示你:
Cannot assign a value to final variable 'aa'
空白final
空白final指的是被声明为final但又未给定初始值的域,无论什么情况,编译器都确保空白final在使用前必须被初始化。比如下面这段代码:
public class FinalTest{ private int i; private final int j; public FinalTest(inti,intj){ this.i=i; this.j=j; } }
必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。
深入了解final关键字
**类的final变量和普通变量的区别:**当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。
下面看一下两个例子:
public static void main(String[] args) { String a = "helloworld"; final String b="hello"; String c = "hello"; String x = b + "world"; String y = c + "world"; System.out.println(a == x); System.out.println(a == y); }
输出结果为true false
大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle?大家可以动动手看看编译之后的代码是什么样的,这里就不做展示了
这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
再看一个例子
public static void main(String[] args) { String a = "helloworld"; final String b; b="hello"; String c = "hello"; String x = b + "world"; String y = c + "world"; System.out.println(a == x); System.out.println(a == y); }
输出结果为 false false,神奇吧,也可以看一下编译之后的class文件,会让你幡然醒悟的(别问,我也是这样的)
被final修饰的引用变量指向的对象内容可变,直接上代码
public static void main(String[] args) { final Student student=new Student(); student.anInt++; System.out.println(student.getAnInt()); } public static class Student{ private int anInt=0; public int getAnInt() { return anInt; } public void setAnInt(int anInt) { this.anInt = anInt; } }
这段代码可以顺利编译通过并且有输出结果,输出结果为1。这说明引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。