• Java学习笔记18---final关键字修饰变量、方法及类


    英语里final这个单词大家都知道是“最终的”意思,其实还有一个意思是“不可更改的”。在Java里,final关键字作“不可更改的”来解释更合适,即由final修饰的东西是“不可更改的”。final可以修饰变量、成员方法和类,还可以修饰方法的参数,但参数归根结底还是变量。下面是详细解释。


    作者: 蝉蝉

    请尊重作者劳动成果,转载请在标题注明“转载”字样,并标明原文链接:

    http://www.cnblogs.com/chanchan/p/7936388.html 

    1.final可以修饰成员变量、局部变量

    (1).final修饰的变量的值不能更改,即不能再次赋值,即使赋的新值与旧值一样也不可以。

    如:

          final int i = 1; //定义int型变量i,并赋初值为1

          //i = 2; //wrong

          //i = 1; //wrong

    注释掉的这两行都不可以,都会出现“The final local variable i can not be assigned.It must be blank and not using a compound assignment.”的错误。

    (2).final修饰的成员变量和局部变量需要在使用前赋值。

        1).对成员变量而言,可以在定义时直接赋初值;

        2).也可以先定义不赋初值,再在构造方法中对其赋值。

    就是说,对象创建好后,该对象的final成员变量要保证是赋了初值的,早点(定义时赋值)、晚点(在构造方法里赋值)都没关系。

    注:第二种情况,如果有多个构造方法就比较麻烦了,每个构造方法都要有赋值语句,否则会出现“The blank final field height may not have been initialized.”的错误。

          3).如果静态成员变量被修饰为final,那么该变量可看成是全局变量,即在类的整个加载期间,其值都不可变。

              如:

              static final String citizenship = "Chinese";

              citizenship既是static又是final的,static说明它是属于整个类的,类加载时就分配内存了(参见笔记9),final说明其值不可变,即,位置固定内容也固定。

    (3).把成员变量和局部变量从变量的类型上来分,

        1).当变量为基本数据类型时,变量的值不可更改,如上面的变量i;

        2).当变量为引用类型时,变量本身的值不可更改,即该变量不能指向其他的对象或数组;

            但该变量指向的对象或数组本身的内容是可以改变的

            如:

                final Person per = new Person(); //定义了一个Person类的对象引用per,并指向了new的对象

                //per = new Person(); //重新创建一个Person类对象,并让per指向它,会出现与上面一样的错误,即final修饰的引用类型变量不能重新赋值

                per.name = "me"; //per指向的对象本身的内容可以更改

    为方便理解起见,请参考下面的内存图:

    2.final可以修饰成员方法

    (1).final修饰的成员方法不能被子类重写,即,当父类的方法为final时,子类不能与父类有方法名、参数类型、参数个数及参数顺序都一样的方法;父类方法为private时除外,详见下面的(3);但子类可以调用父类的final方法。

    见下面的代码:

    Person类的方法:
        final void finalMethod() {
            int i = 2;
            System.out.println("finalMethod: i = " + i);
        }
    
    在TestMain中由Student类的对象引用调用:
    public class TestMain {
        public static void main(String[] args) {
            Student stu = new Student();
            
            stu.finalMethod();
    }

    输出结果为:finalMethod: i = 2

    (2).访问权限为private的方法默认为final的,但子类不可以调用private的方法,关于访问权限修饰符的问题,详见笔记10

    (3).当父类某方法为private final,子类的成员方法与父类的该成员方法重名但仅由final修饰时,这时算不算重写呢?

    Person类的方法:
        private final void priFinalMethod() {
            System.out.println("Person:priFinalMethod");
        }
    
    Student类的方法:
        final void priFinalMethod() {
            System.out.println("Student:priFinalMethod");
        }
    
    TestMain类:
    package human;
    
    public class TestMain {
        public static void main(String[] args) {
            Person per = new Person();
            Student stu = new Student();
            Person per1 = stu;
            
    //        per.priFinalMethod();
            stu.priFinalMethod();
    //        per1.priFinalMethod();
    }
    
    Person类的main方法:
        public static void main(String[] args) {
            Person per = new Person();
            Student stu = new Student();
            Person per1 = stu;
            
            per.priFinalMethod();
            stu.priFinalMethod();
            per1.priFinalMethod();
    }

    TestMain类的输出是:

    Student:priFinalMethod

        1).其中,TestMain类中注释掉的两行都提示该方法不可见;

        2).对于per来说,private的方法仅本类可见,在TestMain类中是不可见的,所以per是不能调用priFinalMethod方法的;

        3).对于per1来说,per1是指向Student对象的引用,per1只能调用Student中重写过的方法及Person类中的方法,由于这里仍然提示该方法不可见,结合2)可知,priFinalMethod方法是没被子类重写的,否则就可以调用了;

    Person类的输出是:

    Person:priFinalMethod
    Student:priFinalMethod
    Person:priFinalMethod

    前两行好理解,最后一行,per1调用的是Person类中的priFinalMethod,进一步说明该方法未被子类重写;

    否则,会优先调用子类的priFinalMethod方法的。

    3.final可以修饰成员方法的参数

    由final修饰的成员方法的参数也是不能更改的,其实参数就是变量,具体参见1即可。

    这里还涉及到形参与实参的概念,具体大家自己了解吧。

    4.final可以修饰类

    由final修饰的类不能被子类继承,其成员方法也默认为final的,但成员变量是可以改变的,见下面代码:

    package human;
    
    public final class FinalClass {
    
        int i = 1;
        
        void test() {
            System.out.println("FinalClass:test");
        }
        
        public static void main( String[] args ) {
            FinalClass ficl = new FinalClass();
            
            System.out.println("ficl.i = " + ficl.i);
            ficl.i = 2;
            System.out.println("ficl.i = " + ficl.i);
        }
    }

    输出结果为:

    ficl.i = 1
    ficl.i = 2

    可见可以修改i的值。

    附测试源码:

    Person类:

    package human;
    
    public class Person {
    //class Person{
        String name;
        int age;
        String gender;
        
        //笔记18:final修饰成员变量,及成员变量为类引用时的情况
        final int height = 160;
    //    final int height;
        final EduBackground edu = new EduBackground();
        
        public Person() {
    //  final height = 160;
        }
        
    //笔记18:final修饰局部变量、修饰成员方法、修饰方法的参数
        //修饰局部变量时,局部变量的值不能改变
        void finalLocal() {
    //        final int i = 1;
            final int i;
            
    //        i = 3;
            final EduBackground edu = new EduBackground();
    //        edu = new EduBackground();
            i = 1;
            System.out.println("finalLocal: i = " + i);
        }
        
        //修饰方法的参数时,参数不能被修改
        void finalArgs(final int i) {
    //        i = 3;
            System.out.println("finalArgs: i = " + i);
        }
        void finalArgs(final EduBackground edu) {
    //        edu = new EduBackground();
            System.out.println("finalArgs: edu");
        }
        
        //修饰成员方法时,成员方法不能被子类重写
        final void finalMethod() {
            int i = 2;
            System.out.println("finalMethod: i = " + i);
        }
        private final void priFinalMethod() {
            System.out.println("Person:priFinalMethod");
        }
    
        public static void main(String[] args) {
            Person per = new Person();
            Student stu = new Student();
            Person per1 = stu;
            
            per.priFinalMethod();
            stu.priFinalMethod();
            per1.priFinalMethod();
        }
    }

    Student类:

    package human;
    
    public class Student extends Person {
        String stuNumber;
        int score;
        
        public Student() {
            
        }
            
    //笔记18:子类不能重写父类被final修饰的方法
    //    final void finalMethod() {
    //        int i = 2;
    //        System.out.println("finalMethod: i = " + i);
    //    }
        final void priFinalMethod() {
            System.out.println("Student:priFinalMethod");
        }
    
    }

    EduBackground类:
    package human;
    
    //public class EduBackground extends FinalClass {
    public class EduBackground {
    
        String primarySchool;
        String secondarySchool;
        String juniorHSchool;
        String seniorHSchool;
        String university;
        
        public EduBackground() {
            
        }
    }
  • 相关阅读:
    C#读写XML no
    ComboBox、ListBox绑定和获取数据 no
    win7 安装oracle 11g no
    2011没有惊天动地 no
    Oracle 删除重复数据只留一条 no
    Oracle 创建用户并分配权限 no
    Oracle 导出、导入某用户所有数据(包括表、视图、存储过程...) no
    谢谢,博客园这么快就审批通过了我的申请!
    Eclipse 中 JAVA AWT相关包不提示问题(解决)
    Eclipse java项目转Maven项目
  • 原文地址:https://www.cnblogs.com/chanchan/p/7936388.html
Copyright © 2020-2023  润新知