final的几个注意点讲解(作者亲测)

首先我们测试final对非静态变量和方法的影响

有final的情况下:

public class FinalTest {
    final int a = 1;
    final String s = "sss";
    final void haha() {
        System.out.println("haha");
        System.out.println(a);
    }
    public static void main(String[] args) {
        FinalTest finalTest = new FinalTest();
    }
}

反编译字节码文件:

public class com.heaboy.mvc.FinalTest {
  final int a;

  final java.lang.String s;

  public com.heaboy.mvc.FinalTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #2                  // Field a:I
       9: aload_0
      10: ldc           #3                  // String sss
      12: putfield      #4                  // Field s:Ljava/lang/String;
      15: return

  final void haha();
    Code:
       0: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #6                  // String haha
       5: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: iconst_1
      12: invokevirtual #9                  // Method java/io/PrintStream.println:(I)V
      15: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #8                  // class com/heaboy/mvc/FinalTest
       3: dup
       4: invokespecial #10                 // Method "<init>":()V
       7: astore_1
       8: return
}

无final的情况下:

public class FinalTest {
    int a = 1;
    String s = "sss";
    void haha() {
        System.out.println("haha");
        System.out.println(a);
    }
    public static void main(String[] args) {
        FinalTest finalTest = new FinalTest();
    }
}

反编译字节码文件:

public class com.heaboy.mvc.FinalTest {
  int a;

  java.lang.String s;

  public com.heaboy.mvc.FinalTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #2                  // Field a:I
       9: aload_0
      10: ldc           #3                  // String sss
      12: putfield      #4                  // Field s:Ljava/lang/String;
      15: return

  void haha();
    Code:
       0: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #6                  // String haha
       5: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_0
      12: getfield      #2                  // Field a:I
      15: invokevirtual #8                  // Method java/io/PrintStream.println:(I)V
      18: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #9                  // class com/heaboy/mvc/FinalTest
       3: dup
       4: invokespecial #10                 // Method "<init>":()V
       7: astore_1
       8: return
}

综上所得,final在两者在haha()方法中有一点点的不同:

  • 我们这里输出的是a:

    • 没有final修饰的变量a,我们需要aload_0,getfield,即加载变量,获取变量的值,然后输出

    • 有final修饰的变量a,我们只需要装载iconst_1或者sipush(这个是大数,比如我们给a刚开始的赋值为10,这就是大数,jvm就不会使用iconst_1,而是选择去用sipush去执行赋值的操作),即直接加载常量,直接输出
    • 理论上有final修饰出的常量调用更快一点

之后我们测试final对静态变量和方法的影响

有final的情况下:

public class FinalTest {
    final static int a = 1;
    final static String s = "sss";
    final static void haha() {
        System.out.println(a);
    }
    public static void main(String[] args) {
        FinalTest finalTest = new FinalTest();
    }
}

反编译字节码文件:

public class com.heaboy.mvc.FinalTest {
  static final int a;

  static final java.lang.String s;

  public com.heaboy.mvc.FinalTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  static final void haha();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: iconst_1
       4: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
       7: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #3                  // class com/heaboy/mvc/FinalTest
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: return
}

没有final的情况下:

public class FinalTest {
    static int a = 1;
    static String s = "sss";
    static void haha() {
        System.out.println(a);
    }
    public static void main(String[] args) {
        FinalTest finalTest = new FinalTest();
    }
}

反编译字节码文件:

public class com.heaboy.mvc.FinalTest {
  static int a;

  static java.lang.String s;

  public com.heaboy.mvc.FinalTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  static void haha();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: getstatic     #3                  // Field a:I
       6: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
       9: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #5                  // class com/heaboy/mvc/FinalTest
       3: dup
       4: invokespecial #6                  // Method "<init>":()V
       7: astore_1
       8: return

  static {};
    Code:
       0: iconst_1
       1: putstatic     #3                  // Field a:I
       4: ldc           #7                  // String sss
       6: putstatic     #8                  // Field s:Ljava/lang/String;
       9: return
}

综上所得,final修饰的变量有不同,两者在haha()方法中也有一点点的不同:

  • final修饰的变量不在静态区当中,而是常量池中
  • 我们这里输出的是a:

    • 没有final修饰的变量a,我们需要getstatic,即加载静态变量,然后输出

    • 有final修饰的变量a,我们只需要装载iconst_1或者sipush即直接加载常量,直接输出

父子继承问题

  1. final修饰的类不能被继承
  2. final修饰的对象和数组,我们是可以修改里面的内容的,但是不能修改地址
  3. 我们不能给父类的变量重新赋值,并且不能重写父类的方法

我们测试第一种情况:会报错,不能继承final修饰的类

public class FinalTest extends FinalDadTest {
    
}

final class FinalDadTest {

}

 

我们测试第二种情况会输出1111:我们可以得出,final修饰的对象和数组,我们是可以修改里面的内容的,但是不能修改地址

public class FinalTest extends FinalDadTest {
    public static void main(String[] args) {
        final FinalTest finalTest = new FinalTest();
        final int[] arr = finalTest.arr;
        arr[0] = 1111;
        System.out.println(arr[0]);// 输出1111
    }
}

class FinalDadTest {
    final int a = 1;
    final int[] arr = new int[10];
    final void haha() {
        System.out.println("sss");
    }
    final void cece() {
        System.out.println("cece");
    }
}


 

我们测试第三种情况:我们会发现我们不能给父类的a重新赋值,并且不能重写父类的方法haha().

public class FinalTest extends FinalDadTest {
    public FinalTest() {
        super.a = 2;
    }
    void haha() {
        System.out.println(a);
    }
    public static void main(String[] args) {
    }
}

class FinalDadTest {
    final int a = 1;
    final void haha() {
        System.out.println("sss");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值