zoukankan      html  css  js  c++  java
  • java—— finall 关键词

           关键字 final 的使用小结:

      final 可以修饰变量,被 final 修饰的变量被赋初始值之后,不能对它重新赋值。

      final 可以修饰方法,被 final 修饰的方法不能被重写。

      final 可以修饰类,被 final 修饰的类不能派生子类。

    final 修饰变量

    final 成员变量

            被 final 修饰的成员变量必须显式指定初始值,而且只能在如下 3 个位置指定初始值。

       定义 final 实例变量时指定初始值;

       在非静态初始化块中为 final 实例变量指定初始值;

       在构造器中为 final 实例变量指定初始值。

      对于普通实例变量, Java 程序可以对它执行默认的初始化,也就是将实例变量的值指定为默认的初始值 0 或 null ;但对于 final 实例变量,则必须由程显式指定初始值。

      下面程序示范了在 3 个地方对 final 实例变量进行初始化。 

    public class FinalDemo {
        
        final String str1 = "直接显式指定初始值";
        final String str2 ;
        final String str3 ;
        {
            str2 = "非静态初始化块中指定初始值";
        }
        public FinalDemo(){
            str3 = "构造器中指定初始值";
        }
    }

    final 类变量

              定义 final 类变量时指定初始值; 在静态初始化块中为 final 实例变量指定初始值; 

    final static String str2 ;
    final static String str3 = "指定初始值";
    static{
    str2 = "非静态初始化块中指定初始值";
    }

    final 局部变量

      final 修饰局部变量时必须显式指定初始值; 

      final String str1 = "指定初始值";

    宏替换 (常量替换)

       对于 final 修饰变量,不管它是类变量、实例变量,还是局部变量,只要定义该变量时使用了 final 修饰符修饰,并在定义该 final 类变量时指定了初始值,而且该初始值可以在编译时就被确定下来,那么这个 final 变量本质上已经不再是变量,而是相当于一个直接量,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。

      事例如下:

    import java.util.Random;
    public class FinalDemo {
        final String str1 = "java";
        final String str2 ;
        final String str3 ;
        {
            str2 = "java";
        }
        public FinalDemo(){
            str3 = "java";
        }
        public void show(){
            System.out.println(str1+str1 == "javajava");//true
            System.out.println(str2+str2 == "javajava");//false
            System.out.println(str3+str3 == "javajava");//false
        }
        public static void main(String[] args) {
            final int a = 30;       
            final int b = 90/3;  //编译期常量,执行替换
            final String c = "30";
            final String str = "java";
            final double d= 99.0;
            final int r = new Random().nextInt(100); //运行时决定初始值
            System.out.println("java30" == "java"+a); //true
            System.out.println("java30" == "java"+b); //true
            System.out.println("java30" == "java"+String.valueOf(a));//false
            System.out.println("java30" == "java"+c); //true
            System.out.println("---------------------------");
            FinalDemo fd = new FinalDemo();
            fd.show();
        }
    }

      a、b、c、str 在编译时期就确定这是个变量的值,因此它们都是“常量”。 String.valueOf(a) 需要调用 String 方法因此编译器无法在编译时就确定变量值,无法执行常量替换。

      上面程序中定义了 3 个 final 实例变量,但只有 str1 在定义该变量时指定了初始值,另外的 str2 、 str3 分别在非静态初始化块、构造器中指定初始值,因此系统不会对 str2 、 str3 执行“常量替换”,但会对 str1 执行“宏替换”。

      上面程序里的 3 条粗体字代码中只有第 1 条才会输出 true ,因为系统会对 str1 执行“宏替换”,也就是说第 3 条粗体字代码相当于: System.out.println ( "Java" + "Java" == "JavaJava" ) ; 上面代码会输出 true 。 

       与此类似的是,对于普通类变量,在定义时指定初始值、在静态初始化块中赋初始值的效果基本一样。但对于 final 类变量而言,只有在定义 final 类变量时执指定初始值,系统才会对该 final 类变量执行“宏替换”。示例如下:

    public class FinalDemo {
        final static String str1 = "java";
        final static String str2 ;
        static{
            str2 = "java";
        }
        public static void main(String[] args) {
            System.out.println("javajava" == str1+str1); //true
            System.out.println("javajava" == str2+str2); //false
        }
    }

      上面程序中定义了 2 个 final 类变量,但只有 str2 在定义该变量时指定了初始值, str1 则在静态初始化块中指定初始值,因此系统不会对 str1 执行“宏替换”,但会对 str2 执行“宏替换”。上面程序里的 2 条粗体字代码中只有第 2 条才会输出 true ,因为系统会对 str2 执行“宏替换”,也就是说第 2 条粗体字代码相当于: System.out.println ( "Java" + "Java" == "JavaJava" );上面代码输出 true 。

      注意:对于运行期常量,它既可是基本数据类型,也可是引用数据类型。基本数据类型不可变的是其内容,而引用数据类型不可变的是其引用,引用所指定的对象内容是可变的。示例如下:

    public class Person {
        private String name;
    
        Person(String name){
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    public class FinalTest {
        private final String final_01 = "chenssy";    //编译期常量,必须要进行初始化,且不可更改
        private final String final_02;                //构造器常量,在实例化一个对象时被初始化
        
        private static Random random = new Random();
        private final int final_03 = random.nextInt(50);    //使用随机数来进行初始化
        
        //引用
        public final Person final_04 = new Person("chen_ssy");    //final指向引用数据类型
        
        FinalTest(String final_02){
            this.final_02 = final_02;
        }
        
        public String toString(){
            return "final_01 = " + final_01 +"   final_02 = " + final_02 + "   final_03 = " + final_03 +
                   "   final_04 = " + final_04.getName();
        }
        
        public static void main(String[] args) {
            System.out.println("------------第一次创建对象------------");
            FinalTest final1 = new FinalTest("cm");
            System.out.println(final1);
            System.out.println("------------第二次创建对象------------");
            FinalTest final2 = new FinalTest("zj");
            System.out.println(final2);
            System.out.println("------------修改引用对象--------------");
            final2.final_04.setName("chenssy");
            System.out.println(final2);
        }
    }
    
    ------------------
    Output:
    ------------第一次创建对象------------
    final_01 = chenssy   final_02 = cm   final_03 = 34   final_04 = chen_ssy
    ------------第二次创建对象------------
    final_01 = chenssy   final_02 = zj   final_03 = 46   final_04 = chen_ssy
    ------------修改引用对象--------------
    final_01 = chenssy   final_02 = zj   final_03 = 46   final_04 = chenssy
    final 修饰引用变量

      备注:Java 会缓存所用曾经用过的字符串直接量。例如执行 String a = "java" ;语句之后,系统的字符串池中就会缓存一个字符串 "java" ;如果程序再次执行 String b = "java" ;,系统将会让 b 直接指向字符串池中的 "java" 字符串,因此 a==b 将会返回 true 。

    final方法

      父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。

    public class Custom extends Person{
        public void method1(){
            System.out.println("Person's  method1....");
        }
        
    //    Cannot override the final method from person:子类不能覆盖父类的final方法
    //    public void method2(){
    //        System.out.println("Person's method2...");
    //    }
    }

    final 类

      如果某个类用final修改,表明该类是最终类,它不希望也不允许其他来继承它。在程序设计中处于安全或者其他原因,我们不允许该类存在任何变化,也不希望它有子类,这个时候就可以使用final来修饰该类了。 对于final修饰的类来说,它的成员变量可以为final,也可以为非final。如果定义为final,那么final数据的规则同样适合它。而它的方法则会自动的加上final,因为final类是无法被继承,所以这个是默认的。

  • 相关阅读:
    升级windows 11小工具
    windows 10更新升级方法
    您需要了解的有关 Oracle 数据库修补的所有信息
    Step by Step Apply Rolling PSU Patch In Oracle Database 12c RAC Environment
    Upgrade Oracle Database Manually from 12.2.0.1 to 19c
    如何应用版本更新 12.2.0.1.210420(补丁 32507738 – 2021 年 4 月 RU)
    xtrabackup 安装、备份和恢复
    Centos_Lvm expand capacity without restarting CentOS
    Centos_Lvm_Create pv vg lv and mount
    通过全备+relaylog同步恢复被drop的库或表
  • 原文地址:https://www.cnblogs.com/SacredOdysseyHD/p/8395195.html
Copyright © 2011-2022 走看看