一、Java — final

  • 任何变量前被 final 修饰就是 final 变量,定义的类前被 final 修饰就是 final 类,任何方法前被 final 修饰就是final方法。

    • 当用 final 修饰一个类时,表明这个类不能被继承。

      “使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的 Java 版本中,不需要使用 final 方法进行这些优化了。“ ——《Java编程思想》第四版第143页

    • final方法是静态绑定的,在编译时就确定好是哪个类的方法,所以final方法比非final方法更快一些。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Main {
      public static void main(String[] args) {
      String a = "xiaomeng2";
      final String b = "xiaomeng";
      String d = "xiaomeng";
      String c = b + 2;
      String e = d + 2;
      System.out.println((a == c));
      System.out.println((a == e));
      }
      }
    • 输出结果:true false。

      • 变量a指的是字符串常量池中的 xiaomeng2;
      • 变量 b 是 final 修饰的,变量 b 的值在编译时候就已经确定了它的确定值,换句话说就是提前知道了变量 b 的内容到底是个啥,相当于一个编译期常量;
      • 变量 c 是 b + 2得到的,由于 b 是一个常量,所以在使用 b 的时候直接相当于使用 b 的原始值(xiaomeng)来进行计算,所以 c 生成的也是一个常量,a 是常量,c 也是常量,都是 xiaomeng2 而 Java 中常量池中只生成唯一的一个 xiaomeng2 字符串,所以 a 和 c 是相等的!
      • d 是指向常量池中 xiaomeng,但由于 d 不是 final 修饰,也就是说在使用 d 的时候不会提前知道 d 的值是什么,所以在计算 e 的时候就不一样了,e的话由于使用的是 d 的引用计算,变量d的访问却需要在运行时通过链接来进行,所以这种计算会在堆上生成 xiaomeng2 ,所以最终 e 指向的是堆上的 xiaomeng2 , 所以 a 和 e 不相等。
    • final修饰的常量普通变量不可变,修饰引用变量引用不可变,引用对象的内容可变。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class A{
      int i = 1;
      }
      public class Main{
      public static void main(String[] args){
      final A a = new A();
      a.i++;
      System.out.println(a.i); //2
      }
      }
    • final关键字的好处:

      • final方法比非final快一些final关键字提高了性能。
      • JVM和Java应用都会缓存final变量。
      • final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
      • 使用final关键字,JVM会对方法、变量及类进行优化。

二、C# — sealed

  • 当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。类似于Java中final关键字。在下面的示例中,类 B 从类 A 继承,但是任何类都不能从类 B 继承。

    1
    2
    class A {}
    sealed class B : A {}
  • sealed 修饰方法或属性,能够允许类从基类继承,并防止它们重写特定的虚方法或虚属性。

    • sealed是对虚方法或虚属性,也就是同override一起使用,如果不是虚方法或虚属性会报出错误:cannot be sealed because it is not an override.

      1
      2
      3
      4
      5
      6
      7
      public class D  
      {
      /* ConsoleApplication1.MSFun.Sealed.D.M()'
      * cannot be sealed because it is not an override
      */
      public sealed void M() { Console.WriteLine("D.M()"); }
      }
    • 防止子类重写特定的方法或属性。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      public class A  
      {
      protected virtual void M() { Console.WriteLine("A.M()"); }
      protected virtual void M1() { Console.WriteLine("A.M1()"); }
      }

      public class B : A
      {
      protected sealed override void M() { Console.WriteLine("B.M()"); }
      protected override void M1() { Console.WriteLine("B.M1()"); }
      }

      public sealed class C : B
      {
      /* ConsoleApplication1.MSFun.Sealed.C.M()':
      * cannot override inherited member 'ConsoleApplication1.MSFun.Sealed.B.M()'
      * because it is sealed */
      //protected override void M() { Console.WriteLine("C.M()"); }

      protected override void M1() { Console.WriteLine("C.M1()"); }
      }