Java中关于static关键字的简介

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。Java中关于static关键字的简介,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

3.static关键字
3.1.概述
  • 关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。
  • 也就是说,既然属于类,就可以不靠创建对象来调用了。
3.2.定义及其使用
  • 类变量:
    • 使用 static关键字修饰的成员变量。
    • 当 static 修饰成员变量时,该变量称为类变量。
    • 该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
  • 静态方法:
    • 使用 static关键字修饰的成员方法,习惯称为静态方法。
    • 当 static 修饰成员方法时,该方法称为类方法 。
    • 静态方法在声明中有 static ,建议使用类名来调用,而不需要创建类的对象。调用方式非常简单。

      静态方法调用的注意事项:

      • 静态方法可以直接访问类变量和静态方法。
      • 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。
      • 静态方法中,不能使用this关键字
      • 静态方法只能访问静态成员。
  • Example
public class Student_static {
    public static void main(String[] args) {
        // 访问类变量
        System.out.println(Student.numberOfStudent);
        // 调用静态方法
        Student.showNum();
    }
}
3.3.静态代码块
  • 定义在成员位置,使用static修饰的代码块{ }。
  • 位置:类中方法外。
  • 执行:随着类的加载而执行且执行一次,优先于main方法和构造方法的执行。
  • 作用:给类变量进行初始化赋值,调用方法等。

    static 关键字,可以修饰变量、方法和代码块。在使用的过程中,其主要目的还是想在不创建对象的情况下,去调用方法。

Example:

public class Game {

    public static int number;
    public static ArrayList<String> list;

    static {
        // 给类变量赋值
        number = 2;
        list = new ArrayList<String>();
        // 添加元素到集合中
        list.add("张三");
        list.add("李四");
    }
}
3.4.代码块
3.4.1.普通代码块
  • 在Java中,使用大括号”{}“括起来的代码被称为代码块,根据其位置和声明方式的不同,可以分为:
    • 局部代码块:对于变量的作用域有明确的限制,强制变量成为局部变量,但实际意义不大,严重影响代码可读性,却对内存回收帮助极小
    • 构造代码块:创建对象时,对成员变量进行默认初始化赋值,优先于构造方法运行。
    • 静态代码块:在类加载时,对于静态成员变量进行赋值(且只能给静态成员变量赋值),与静态成员变量显式初始化语句执行优先级相同,谁在上边谁先执行。
    • 同步代码块(多线程使用)
  • 代码块在实际开发中,使用频率并不高,可替代性也很强,但是由于其迷惑性极强,常年出没于各种面试题中。
3.4.2.构造代码块与静态代码块
public class ExerciseBlock {
    static {
        System.out.println("静态代码块!");
    }
    {
        System.out.println("构造代码块!");
    }
    public static void main(String[] args) {
        System.out.println("main方法开始执行!");
        Star s = new Star();
        System.out.println(Star.name);
    }
}

class Star{
    static {
        name = "杨幂";
        System.out.println("我喜欢杨幂");
    }
    static String name = "赵四";  //静态成员变量
    {
        name = "杨超越";
        System.out.println("我喜欢杨超越");
    }
    public Star() {
        name = "123";
        System.out.println("Star:构造器!");
    }
}

//运行结果:
    静态代码块!
    main方法开始执行!
    我喜欢杨幂
    我喜欢杨超越
    Star:构造器!
    123
  • 解释:首先,main方法所在ExerciseBlock类要加载进入方法区,静态代码块随着ExerciseBlock类加载而执行,输出 静态代码块! 语句,继而,main方法栈帧进入栈中,main方法开始执行,输出 main方法开始执行! 语句,Star类的class文件加载进入方法区,Star的静态变量String name 随之加载进入方法区,并且初始值为 null ,因为静态代码块在静态变量赋值语句的上边,所以静态代码块先执行,给name赋值为 杨幂 ,并输出 我喜欢杨幂 ,随后,静态变量的赋值语句执行,修改name为 赵四 ,接着,在堆上创建Star类的s对象,构造代码块开始执行,将name赋值为 杨超越 ,输出 我喜欢杨超越 ,最后,构造方法开始执行,将name最后修改为 123 ,并输出 Star:构造器!,因为主方法的输出语句在最后,所以最后输出 123 ,至此执行完毕。

    注:

    ​ 在程序运行中,静态代码块与静态变量的初始化赋值语句,虽然在真正的程序编写中,很少会给静态变量直接赋初始值,但在面试中会偶尔考察,如上述代码中,静态代码块和静态变量显式初始化语句的优先级是一样的,都是随着类加载进方法区而执行,所以按代码的书写顺序执行,谁在上边谁先执行,而构造代码块和构造方法,都是创建了对象以后才开始执行,且构造方法永远最后执行。

    ​ 个人理解,构造方法之所以永远最后执行,是为了程序员进行初始化赋值的时候,保证所赋值的内容永远是想要的内容。

    ​ 另:静态的内容,只会随着类加载而执行,因此,类只需加载一次,所以静态的内容也只会执行一次。

  • 额外补充:
    • 对于默认初始化赋值,创建对象的时候第一件事情就是默认初始化,这时候成员变量只会赋默认初值,而调用构造方法的时候,不管是隐式的super还是显式的this,都会追溯到父类,在父类调用自己的构造方法之前,成员变量初始化(比如类中定义了int age = 10)这时候就会开始,父类调用完毕后,子类调用自己的构造方法,同理,子类调用之前,也会给自己的成员变量赋值。

class Father {
      int i = 10;
      public Father() {
          System.out.println(getI());
      }
      public int getI() {
          return i;
      }
    }
    
  class Son extends Father {
  int i = 100;
  public Son(int i) {
      this.i = i;
  }
  public int getI() {
      return i;
  }
  
  }
//对于以上代码,在主方法中,执行Father father = new Son(1000),输出结果是0;
//父类方法被子类覆盖,即使在父类中调用,调用到的也是子类方法,而此时父类对象还在初始化过程中,子类对象更是还未开始初始化,其成员变量的值还是默认值。
  
  public class MyStack {

  int INIT_CAPACITY = 10;// 默认初始容量

  
  public MyStack(){

  // 如果使用者不传数组的初始长度, 默认是10

  
  //        this.arr = new Object[INIT_CAPACITY];
//        this(INIT_CAPACITY);  //报错Cannot reference 'MyStack.INIT_CAPACITY' before supertype constructor has been called
  }
  public MyStack(int capacity){
      // 参数检查
      if (capacity <= 0 || capacity > MAX_CAPACITY){
          throw new IllegalArgumentException("capacity is Illegal");
      }
      arr = new Object[capacity];
  }
  }
//对于以上代码,虽然此时MyStack的成员变量,已经有了默认初始值,但是,父类的构造方法,即Object的构造方法,还没有被调用,此时卡在了this中,
//子类变量依赖于父类存在,JVM不允许这样做,所以直接报错,不能在super()被调用之前使用自己的成员变量。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181097.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!