面向对象通识16(final修饰符)

final可以修饰变量(各种变量)、方法、类

finalabstract是互斥的,无法同时出现。

特性

final修饰类变量

  • 该变量被赋初始值之后,不能被重新赋值。
  • 该变量必须被赋值

final修饰成员变量

  • 对于普通的成员变量,可以不显示指定的初始值,系统会位置分配默认的初始值。

(该初始值分配规则与数组元素的初始值分配规则完全相同)

  • 对于final修饰的成员变量,程序员必须分配指定的初始值

    • final实例变量,必须显示指定的初始值。只能在以下3个位置的其中之一指定:

      • 定义时指定初始值

      • 实例初始化块

      • 构造器
        上面三个位置本质上都是要还原到构造器
        不能在普通方法中赋值!

        1. public class Final实例变量 {
        2. final int age=20;
        3. final String s="java";;
        4. final long lg;
        5. {
        6. lg=2333333;
        7. }
        8. public void sc(){
        9. }
        10. }
  • final修饰的类变量,必须显示指定的初始值。只能在以下2个位置的其中之一指定:

    • 定义时指定初始值

    • 类初始化快
      本质上都是在类初始化快中指定初始值
      实例初始化快可以访问final类变量,但不能指定初始值

      1. public class Final类变量 {
      2. static final int a=10;
      3. static final String m;
      4. static {
      5. m="z";
      6. }
      7. void a(){
      8. System.out.println(m);
      9. }
      10. }
  • 对于非final修饰的局部变量,程序员必须指定初始值,然后才能使用

  • 对于final修饰的局部变量,程序员必须指定初始值,然后才能使用,与前者唯一的区别就是不能被重新赋值

  • 如果final修饰的是引用类型的变量——
    final只能保证该引用变量本身不会被重新赋值,该变量所引用的对象完全可以被修改

  1. public class Final引用类型 {
  2. public static void main(String[] args) {
  3. final Pig p=new Pig("white",4);
  4. //只能保证p不能被重新赋值
  5. p.setColor("black");
  6. p.setWeight(5);
  7. System.out.println(p.getColor());
  8. System.out.println(p.getWeight());
  9. }
  10. }
  11. class Pig{
  12. private String color;
  13. private int weight;
  14. public Pig(String white, int i) {
  15. }
  16. public void setColor(String color){
  17. this.color=color;
  18. }
  19. public void setWeight(int weight){
  20. this.weight=weight;
  21. }
  22. public String getColor(){
  23. return this.color;
  24. }
  25. public int getWeight(){
  26. return this.weight;
  27. }
  28. }

final修饰宏替换的变量

条件

  • 变量有final修饰
  • 声明变量时指定初始值
  • 变量的初始值可以在编译的时候确定下来(初始值的表达式中没有变量、方法调用等)

这个变量就会消失,所有出现该变量的地方,在编译的时候就会出现该变量的值

  1. public class 宏变量 {
  2. public static void main(String[] args) {
  3. final int MAX=100;
  4. //有final修饰,指定了初始值,并且初始值在编译的时候就可以确定
  5. }
  6. }

举例:

  1. public class 宏变量 {
  2. public static void main(String[] args) {
  3. String a="a";
  4. String b="a";
  5. System.out.println(a==b);
  6. String s1="accd";
  7. String s2="ac"+"cd";//编译阶段就会计算结果
  8. System.out.println(s1==s2);
  9. String s3="ac";
  10. String s4="cd";
  11. String c=s3+s4;//s3和s4是变量,在运行的时候才会计算
  12. System.out.println(c==s1);
  13. final String s7="ac";
  14. final String s8="cd";
  15. String d=s7+s8;//s7和s8有final修饰并在声明的时候已经指定了初始值,出现了宏替换
  16. System.out.println(d==s1);
  17. }
  18. }
  19. /*
  20. true
  21. true
  22. false
  23. true
  24. */

例题2

  1. public class 例题 {
  2. public static void main(String[] args) {
  3. final String s1="wyd";
  4. final String s2=s1+" is";
  5. final String s3=s2+" unjuanable";
  6. System.out.println(s3);
  7. }
  8. }
  9. /*
  10. wyd is unjuanable
  11. */

上述代码经过了3次宏替换

final修饰方法

final修饰的方法可以被重载,可以被子类调用,但不能被重写(避免该方法被子类破坏)

举例1

  1. class A{
  2. public final void info(){
  3. System.out.println("info");
  4. }
  5. }
  6. public class 调用方法 extends A {
  7. @Override
  8. public void info(){
  9. System.out.println("change");
  10. }
  11. }
  12. /*
  13. 'info()' cannot override 'info()' in 'Final宏变量.A'; overridden method is final
  14. */

举例2

  1. class Foo {
  2. //private方法已经隐藏在该类的内部不可能被重写,子类无法访问
  3. private final void test(){
  4. System.out.println("2333");
  5. }
  6. }
  7. public class F1 extends Foo{
  8. public void test()
  9. {
  10. System.out.println("32222");
  11. }
  12. public static void main(String[] args) {
  13. F1 a=new F1();
  14. a.test();
  15. }
  16. }
  17. /*
  18. 32222
  19. */

在例2中 private方法已经隐藏在该类的内部不可能被重写,子类无法访问,

逻辑上final在这里是多余的。