zoukankan      html  css  js  c++  java
  • 关于 static 和 final 的一些理解

    今天主要回顾一下 static 和 final 这两个关键字。

    1. static  -  静态
    修饰符 - 用于修饰数据(变量、对象)、方法、代码块以及内部类。
       
        1.1 静态变量
    用static修饰变量,称之为静态变量,也叫类变量。在类加载的时候加载到了方法区,并且在方法区中被赋予了默认值。静态变量是先于对象出现的,所以习惯上是通过类名来调用静态变量。每一个对象存储的是这个静态变量在方法区中的地址,所以静态变量是被这个类的所有对象所共享的。
    静态变量能否定义到构造方法中? --- 不能。静态变量是在类加载的时候出现,先于对象出现。构造方法在创建对象的时候执行。
    注意:
    1.类是加载到方法区中的
    2.类是在第一次使用的时候才加载,加载之后就不会移除
     
     
    练习:定义一个类,统计这个类创建对象的个数。
    复制代码
    package cn.tedu.staticx;
    
    public class StaticExer {
        public static void main(String[] args) {
            new SDemo();
            new SDemo();
            new SDemo();
            System.out.println(SDemo.count);
        }
    }
    
    class SDemo{
        static int count = 0;//如果不用 static 则每一个对象创建的时候,都会赋值为 0 ,然后再加一次,只能是1
        public SDemo(){
            count++;
        }
    }
    复制代码
       1.2 静态方法
    用 static 修饰的方法,称之为静态方法。静态方法随着类的加载而加载到方法区中,但是在方法区中不执行只存储,在方法被调用的时候到栈内存执行。静态方法先于对象存在,所以习惯上是通过类名来调用静态方法。
    main    Arrays.sort();   System.arraycopy();
     
    静态方法中可以定义静态变量吗? --- 不能 --- 静态方法在调用的时候执行,静态方法执行的时候里面的变量才能初始化;静态变量是在类加载的时候初始化。
    静态方法中能否使用 this/super? --- 不能 --- this 代表当前在活动的对象,静态方法先于对象存在
    能否在静态方法中直接使用本类中的非静态方法/非静态属性? --- 不行
    静态方法可以重载吗? --- 可以(讲重载的时候,默认都是写的 public static )
    静态方法可以被继承吗?--- 可以
    静态方法可以重写吗?--- 不可以
     
    静态方法虽然不能被重写,但是父子类中可以存在方法签名一致的静态方法 --- 静态方法的隐藏(hide)
    注意:父子类中可以存在方法签名一致的方法,要么都是非静态(重写)要么都是静态(隐藏)
     
    复制代码
    package cn.tedu.staticx;
    
    public class StaticDemo5 {
        public static void main(String[] args) {
            System.out.println(D.i);
        }
    }
    
    class D{
        static int j = 5;//先将静态变量i放入方法区,并且标记一个值为0;在初始化阶段,再检查i是否有初始值0,如果没有初始值,则将标记值0赋值进去;
                        //如果有初始值,则将初始值设置进去,抛弃标记值,然后顺次执行静态代码块,将静态变量i的值改为7
        {
            j = 7;
        }
        
            //在类加载阶段,由于i处于一个标记值状态,所以实际上是无值的,所以此时不允许直接操作
        static{      //先将静态变量i放入方法区,并且标记一个值为0;在初始化阶段,先执行静态代码块,对于i=7;并不是将7直接赋值给i;检查i是否有初始值,
                    //如果没有初始值,则将标记值7赋值进去;如果有初始值则抛弃标记值,将初始值5赋值进去
            i = 7;
            i = 9;
            //i -= 5;//进行运算就报错了,类在加载的时候是分了 5 个阶段:准备(加载这个类中的静态变量并标记默认值) -> 初始化(初始化静态变量,执行静态代码块)
        }
        static int i = 5;
    }
    复制代码
        1.3 静态代码块
    用static{ }包起来的代码 --- 在类加载的时候执行一次
    执行顺序:父类静态 -> 子类静态 -> 父类非静态 -> 父类的构造方法 -> 子类非静态 -> 子类的构造方法
     
     
    2. final
    修饰符 --- 修饰数据、方法以及类
    final 修饰数据的时候 ---- 常量 ->定义好之后不可改变。如果 final 修饰的是基本数据类型的数据,那么指的是实际值不可变;如果 final 修饰的引用类型的数据,那么指的是地址不可变,但是对象中的元素或者属性值可以改变 --- 对于成员常量要求在对象创建完成之前给值;对于静态常量而言要求在类加载完成之前给值。
    arr.length    System.in    System.out
    注意:常量的存储和方法区中的运行时常量池有关。
     
    final修饰方法 --- 最终方法,能被继承但是不可被重写/隐藏,能被重载
    final修饰类 --- 最终类  ---  不能被继承(里面的方法现阶段也不能被重写)System   
    复制代码
    package cn.tedu.finalx;
    
    import java.util.Arrays;
    
    public class FinalDemo1 {
        public static void main(String[] args) {
            
            //final int i = 9;
            final int i;
            i = 13;
            
            final int[] arr = {3,6,1,7,0};
            arr[1] = 8;//并没有报错,因为 arr 是一个对象 -> 地址不可变
            //arr = new arr[4];//报错了,地址改变了
            
            //arr.length = 9;
            
            //changeValue(i);
            System.out.println(i);
            
            expand(arr);//一开始主函数中有一个 arr 了,指向堆内存中的某个地址,当调用这个方法后,方法中的 arr 会指向这个地址,但改变后,
            System.out.println(arr.length);//方法中的arr指向新的地址,而主函数中的那个还是指向原来的地址(方法用完就释放堆内存中的资源)
        }
    
        //在这个方法中并没有将参数i定义为常量
        public static void changeValue(int i){
            i++;
        }
        
        public static void expand(int[] arr){
            arr = Arrays.copyOf(arr, arr.length * 2);
        }
    }
    
    class A{
        
        //定义成员常量
        //成员常量 i 在对象完成创建之前给值
        final int i = 6;
        int j;
        
        //静态常量必须在类加载完成之前给值
        static final int k = 0;
        
        {
            //i = 10;
        }
        
        public A(){
            //i = 10;
        }
    }
    
    /*class A{
        
        private final int i;
        
        {
            //i = 4;
        }
        
        public A(){
            this(5);//是对的
            //this.i = 0;也是对的,两次调用是互不影响的
        }//无参构造中未初始化常量
        public A(int i){
            this.i = i;//常量的二次赋值
        }
    }
    
    */
    复制代码
     

    ---恢复内容结束---

  • 相关阅读:
    Centos 安装配置iscsi
    Centos 部署Keepalive高可用软件
    Centos 编译安装Haproxy
    Centos 安装 Moosefs文件系统
    docker 存储
    hadoop碰到的 一个问题
    使用curl命令操作elasticsearch
    kafka集群下线broker节点实践方法(broker topic 迁移)
    kafka 安装
    redis3.2.11 安装
  • 原文地址:https://www.cnblogs.com/hanease/p/15677103.html
Copyright © 2011-2022 走看看