zoukankan      html  css  js  c++  java
  • Java基础之final、static关键字

    一、前言

      关于这两个关键字,应该是在开发工作中比较常见的,使用频率上来说也比较高。接口中、常量、静态方法等等。但是,使用频繁却不代表一定是能够清晰明白的了解,能说出个子丑演卯来。下面,对这两个关键字的常见用法做点总结记录,方便之后的回顾以及突击知识点。

    二、关键字 final

      final,一如字面意思 “最终的”,大体在 Java 中表示 “不可变的”。可用来修饰类、方法、方法参数以及变量。

      1、修饰类

       final 在修饰类的时候,代表的是此类不能被继承。也就是说如果一个类确定不会被继承使用,则可以设计成 final类型的。典型的例子就是 String 类。

      2、修饰方法

      final 修饰的方法,能被继承,但是不能重写。可以重载。

      3、修饰方法参数

      final 在修饰方法参数的时候,表示的是在执行方法的内部,不能够去改变参数的值。但是如果是引用对象,是可以改变应用对象的属性值。

      4、修饰变量

      final 在修饰变量,代表的是不可变,也即是常说的 “常量”。 final 在修饰的时候,允许一次赋值,之后在生命周期类,不允许对其进行修改。

      修饰变量存在两种情况:基本类型的数据 和  对象数据。在修饰基本类型数据的时候,值是不可变的。在修饰对象数据的是,对象的引用是不可改变的,但是,可以修改对象内部的属性值。

      final 修饰的变量必须在使用前进行初始化,一种方式是在声明的时候就给出默认值。还有一种就是通过构造方法去设置。

      5、代码示例

    package com.cfang;
    
    import java.util.Calendar;
    
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class T3 {
        
    
        public static void main(String[] args) {
            // -- 修饰变量
            final int b = 0;
            /**
             *     编译报错:The final local variable b cannot be assigned. It must be blank and not using a compound assignment
             */
    //        b = 2;
            
            // -- 修饰方法参数
            DemoCls cls = new DemoCls();
            cls.setAge(10);
            log.info("democls age : {}", cls.getAge());
            int a = 10;
            sayHello(a, cls);
            log.info("after call sayHello, democls age : {}", cls.getAge());
        }
        
        private static void sayHello(final int a, final DemoCls cls) {
            /**
             *     编译报错:The final local variable a cannot be assigned. It must be blank and not using a compound assignment
             */
    //        a = 11;
    //        cls = new DemoCls();
            
            cls.setAge(11);
        }
    }
    
    @Data
    class DemoCls{
        private int age;
    }
    
    // -- 修饰方法
    @Slf4j
    class Person {
        public final void saySth() {
            log.info("i am person");
        }
    }
    
    @Slf4j
    class Male extends Person{
        /**
         *     编译出错 : Cannot override the final method from Person
         *     修饰的方法不能够被重写
         */
    //    public final void saySth() {
    //        log.info("i am male");
    //    }
        
        public final void saySth(String msg) {
            log.info("i am male");
        }
    }

      其中,修饰方法参数,如果是引用对象,是可以改变对象的属性值,这一点也很好理解:cls 是引用变量,final 修饰引用变量,只是限定了此引用变量 cls 的引用不能改变,而实际引用的对象的本身的值是可以进行修改的。文字语言组织可能不是很清晰,如下图所示,一目了然的就知道说要表述的意思了。

      

    三、关键字 static

      static,静态的。在 Java 中,static 通常可被用于修饰 变量、方法以及代码块。

      1、修饰变量

      static 修饰的变量,叫做静态变量。static 变量被所有类对象共享,在内存中仅一份,随着类的初始化而被加载。与之对应的非静态变量,是属于每个实例对象本身,内存中存在多份,相互间不影响。

      2、修饰方法

      static 修饰的方法,叫做静态方法。调用静态方法,不依赖于实例对象就可以进行访问,所以,静态方法是没有 this的。由于此特性以及非静态方法依赖于实例对象调用,所以静态方法中是不能够直接使用非静态的成员属性和方法。与之相反的是,非静态方法是可以直接访问使用静态成员变量和方法。同样的,静态方法也是没有 super 的。可以一句话总结下:由于 static 和具体的实例对象无关,而 this、super和具体的实例对象息息相关,所以,static 和 this、super 势如水火,一如白天与黑夜。

      3、修饰代码块

      static 修饰代码块,在类初始化加载的时候,会按照 static 块的顺序进行加载,并且,生命周期内,只加载一次。基于此特性,可以设计优化程序的性能,一些只需要一次性初始化加载的内容,就可以放在 static 块中进行。

      4、代码示例

    package com.cfang;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class T4 {
        
        private static int a;
        private static int b;
        private static int c;
        
        static {
            log.info("init value a");
            a = 10;
        }
        
        {
            /**
             *     普通代码块,依赖于实例对象
             */
            log.info("init value c");
            c = 12;
        }
    
        public static void main(String[] args) {
            // -- 静态方法调用非静态
            /**
             *     不可直接访问
             */
    //        sayHello1();
            new T4().sayHello1();
            
            // -- 静态方法直接调用
            sayHello();
            
            // -- 静态代码块初始化资源
            log.info("value a : {}", a);
            log.info("value b : {}", b);
            log.info("value c : {}", c);
        }
        
        private static void sayHello() {
            log.info("say hello");
        }
        
        private void sayHello1() {
            log.info("say hello1");
            // -- 非静态方法直接调用
            sayHello();
        }
        
        static {
            log.info("init value b");
            b = 11;
        }
    }

      5、static 常见误区

    package com.cfang;
    
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class T5 {
        
        private static int a = 10;
    
        public static void main(String[] args) {
            new T5().printVal();
            
            //-- The field DemoCls01.b is not visible
            DemoCls01.b;
        }
        
        private void printVal() {
            int a = 11;
            log.info("value a : {}", this.a);
        }
    }
    
    @Data
    class DemoCls01{
        private static int b;
    }

      5.1、static 的 this

      上述代码中,最终运行 printVal 方法,输出的结果是 :value a : 10  。 其实这也很好理解: this 指代的当前对象,而通过 new T5().printVal() 调用的话,this 指代的就是当前新创建的实例对象,static 修饰的变量本身是被所有类对象所共享的,而 printVal 方法中 a 属于局部变量,跟 this 实例对象并没有关联。所以,输出的就是 10。

      5.2、static 与 可见性

      static 并不能改变变量或者方法的可见性。上述代码中,main 方法中,DemoCls01.b 会编译报错。

      5.3、static 与 局部变量

      Java规范中,明确说明了 :static 关键字不可修饰局部变量。

    四、总结

      final 和 static ,联合使用修饰属性表示一旦给值,就不可修改,并且可以通过类名访问;修饰方法,表示该方法不能重写,可以在不new对象的情况下调用。

      突然想到,接口 interface 中,成员变量的默认修饰符为 public static final,方法的默认修饰符 public abstract 。

  • 相关阅读:
    centos 7 安装mqtt 修改用户名和密码
    5-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案升级篇(,远程升级GPRS内部程序)
    ESP8266开发综合篇第十四节(LUA)-8266作为TCP服务器,Android客户端连接,显示温湿度,控制继电器
    ESP8266开发综合篇第一节(LUA)-下载和刷固件
    springMvc源码学习之:spirngMvc的拦截器使用
    Java Web学习(1): 客户端请求、服务器响应及其HTTP状态码
    HttpServletRequest常用获取URL的方法
    java多线程:并发包中的信号量和计数栓的编程模型
    springMvc源码学习之:利用springMVC随时随地获取HttpServletRequest等对象
    springMvc源码学习之:spirngMvc的参数注入的问题
  • 原文地址:https://www.cnblogs.com/eric-fang/p/11593570.html
Copyright © 2011-2022 走看看