• Java的static和final关键字的用法


    static关键字的用法

      static的意思是“’静态的”,在java里面可用于修饰属性和方法。

      static关键字的应用应注意以下几种情形:  

        1.static作用于某个字段,一个static字段对每个类来说只有一份存储空间,而非static字段是每个对象有一份存储空间。

        2.static作用于方法的重要用法是不需要创建任何对象直接调用该static方法,这对于main()方法很重要。

        3.static不能应用于局部变量。

        4.Java中禁止使用全局方法,所以引入static方法通过类本身来直接调用。

    package cn.wangze.test;
    
    class Demo{
        public static int i = 19;
    }
    
    public class staticDemo {
        private static Demo demo1 = new Demo();
        private static Demo demo2 = new Demo();
        public static void main(String[] args){
            System.out.println(Demo.i);     //19
            System.out.println(demo1.i);    //19
            System.out.println(demo2.i);    //19
            demo1.i++;
            System.out.println(Demo.i);        //20
            System.out.println(demo1.i);    //20
            System.out.println(demo2.i);    //20
            Demo.i++;
            System.out.println(Demo.i);        //21
            System.out.println(demo1.i);    //21
            System.out.println(demo2.i);    //21
        }
    }

      上面程序的输出结果验证了上面两条,带有static关键字的数据在内存中占有一块固定内存地址,你可以用类名直接调用,也可以创建对象来调用,推荐ClassName.method()来调用。当我们改变它的值,任何地方的调用也会随之改变。

      Java系统自带的Math、UUID、Class等常用的工具类就是用的这种方式。

     为什么要将方法和变量都写成静态的。
     因为,这些方法我只是想调用一下,不需要牵扯工具类中的任何属性和变量,所以,我就没有必要实例化了(new)。既然不需要实例化了,那么就用静态就行了。

      你也可以在实际项目中根据业务需求来声明自己的工具类,只需要加入static关键字,引入该类后使用类名.方法名()调用即可。

      需要注意的一点是,类的加载和初始化过程中,带有static的数据会最先加载并调用,其次是构造器的加载,最后才是普通成员变量和方法的加载。

    final关键字的用法

      final意味着"不可改变的",一般应用于数据、方法和类。

    final数据

        当数据是基本类型时,意味着这是一个永不改变的编译时常量,一个在运行时被初始化的值,你不希望它改变。

        当数据是引用类型时,用static和final修饰表示这是只占据一块不能改变的内存空间。

        有一条约定成俗的规定是使用stati和final修饰的变量即编译期常量应该用全部大写字母表示,例如:

    package cn.wangze.test;
    
    import java.util.*;
    
    class Value{
        int i;
        public Value(int i){
            this.i = i;
        }
    }
    
    public class FinalData {
        private static Random rand = new Random(47);
        private String id;
        public FinalData(String id){
            this.id = id;
        }
        private final int value_one = 9;
        private static final int VALUE_TWO = 99;
        public static final int VALUE_THREE = 39;
        private final int i4 = rand.nextInt(20);
        static final int INT_5 = rand.nextInt(20);
        private Value v1 = new Value(11);
        private final Value v2 = new Value(22);
        static final Value V3 = new Value(33);
        private final int[] a = {1,2,3,4,5,6};
        @Override
        public String toString(){
            return id+", i4="+i4+",INT_5 = "+INT_5;
        }
        public static void main(String[] args){
            FinalData fd1 = new FinalData("fd1");
            //fd1.value_one++; 错误,final修饰的基本类型数据的值不能改变
            fd1.v2.i++;
            fd1.v1 = new Value(9); //可以操作,因为v1不是final数据
            //fd1.v2 = new Value(0);  错误,final修饰的引用类型数据的内存地址不能改变
            //fd1.v3 = new Value(5);  错误,final修饰的引用类型数据的内存地址不能改变
            //fd1.a = new int[3];  /错误,final修饰的引用类型数据的内存地址不能改变
            System.out.println(fd1);   // fd1, i4=15,INT_5 = 18
            System.out.println("creating new FinalData");
            FinalData fd2 = new FinalData("fd2");  
            System.out.println(fd1);     //fd1, i4=15,INT_5 = 18
            System.out.println(fd2);    //fd2, i4=13,INT_5 = 18
        }
    }

        上面例子验证了final修饰的基本数据类型和引用数据类型的区别。根据i4和INT_5的输出值可以得出结论,在编译期我们不能因为数据是final 的就可以知道它的值,只有在运行时才会确定它的值。同时这里也展示了静态和非静态的区别,带有static关键字的数据在装载时被初始化,非静态的数据是在创建对象时间初识化的。例如:

    package cn.wangze.test;
    
    class useDemo{
        private int i;
        public useDemo(int ii){
            i = ii;
        }
    }
    
    public class BlankFinal {
        private final int i = 9;
        private final int j;
        private final useDemo ud;
        public BlankFinal(){
            j = 1;
            ud = new useDemo(10);
        }
        public BlankFinal(int x){
            j = 2;
            ud = new useDemo(x);
        }
        public static void main(String[] args){
            new BlankFinal();
            new BlankFinal(55);
        }
    }

       上面例子我们在定义final变量是没有给其赋值,这并没有错,但是一定要在构造器中给其赋值,不然编译都不会通过。

      2、fianl参数

        当我们把方法传入的形参定义为fianl时候,代表我们并不想在方法内部改变此参数的引用。

        public void change( final useDemo u2){
            u2.i = 20;
            //u2 = new useDemo(20); 报错
        } 

        事实是当我们不带有final关键字时,函数内部的引用改变也不会对外界的实参产生影响,所以我认为这里final的作用是编译期的阻拦,起到一个警示的作用。

      3、fianl方法

        一般我们使用final方法的目的就是防止子类对该类方法的覆盖或修改。

        类中的所有private方法都隐式的制定为final的。因为private方法只会在本类显示,即使是子类也不能操作该方法。有时候我们在子类中声明与父类private方法相同名称的方法,这样并不会报错,实际上我们并没有覆盖或者修改父类的private 方法,它只是一个和父类private方法具有相同名称的新方法。

      4、fianl类

        一般我们使用final类的目的就是说明我们不打算用任何类继承该类,即不希望该类有子类。

        带有final关键字的类,其内部所有方法和数据都是隐式带有final关键字的,因为没有类可以继承该类,代表着任何外界因素可以改变它的数据。

      总结:

        在我们设计程序的时候,会根据业务需求来决定是否对数据或方法或类带有static和final关键字,这很重要,从另一个角度来说,final和static关键字的合理应用确实可以提高程序的效率,减少内存的消耗,当我们了解了类的初始化和加载过程,可能会对final和static有一个更加直观的认识。

  • 相关阅读:
    Python笔记:日期时间获取与转换
    算法笔记:递归、动态规划
    容器技术介绍:Docker Dockerfile语法与指令
    Netdiscover网络扫描工具
    持续集成:jenkins + pytest + selenium + Git + Allure自动化测试
    MySQL数据库基础入门
    Parameters 至少一个参数没有指定
    C/C++ 延时函数 (标准库)
    TabController控件测试
    contentEditable
  • 原文地址:https://www.cnblogs.com/blue-wz/p/7399608.html
Copyright © 2020-2023  润新知