【JAVA基础】static关键字


static关键字定义

  • static修饰的代码属于类,不被修饰的代码属于对象
  • 定义的变量存储在方法区的静态常量池中

为什么设计static关键字

方便类直接去调用某些方法

如果方法和变量属于非静态的方法,他们只有在对象中才会被分配内存空间,也就是说只有对象才能调用,而以下代码只会以信息的方式存储在方法区中:

public class A {
    
    public void run(){
        System.out.println("111");
    }

    public void fly(){
        System.out.println("222");
    }
}

调用方式只能通过对象的方式调用:

A a = new A();
a.run(); 
a.fly();
A.run(); // 会报错,提示将run()改为static 如下图:

报错
不用static修饰的内存图

当我们加上static关键字之后:

public class A {

    public static String name = "admin";
    
    public static void run(){
        System.out.println("111");
    }

    public static void fly(){
        System.out.println("222");
    }
}

我们就可以通过类来调用我们的方法和变量:

A.name = "xxx"; 
A.run();
A.fly(); // 不再报错

但是同时也可以通过对象来调用这些变量和方法,因为对象来源于类,但是这种情况下不推荐,更推荐通过类调用
在这里插入图片描述

static关键字使用方法

  1. 修饰变量

    static修饰的变量属于类变量,存储在方法区中的静态常量池中,被所有对象共享

  2. 修饰方法

    • static修饰的方法无法调用非静态方法 如果想要在main方法中调用

      1. 在非静态方法上加入static关键字
      2. 在main()方法中创建对象
    • 在非静态方法中可以调用静态方法 原因如下

      非静态方法在表达是已经创建了对象,而有对象一定有类,静态方法修饰的方法属于类方法,存储在方法区中的静态常量池中,那么可以被对象共享并调用

  3. 修饰代码块

    所修饰的代码块在main()方法之前运行,目的是优化程序执行

    举个栗子

    例1

    /*
    *  流程
    *  1. 程序执行先去找main()方法启动程序
    *  2. 首先先去扫描Base类,发现Base类没有父类
    *  3. 将Base.class加载进方法区,此时Base类中的static代码块执行
    *  4. main方法入栈--->执行 new test1();去创建test1类对象,扫描test1类,发现有父类Base类,但是已经扫描过了不再进行扫描
    *  5. 将test1.class加载进方法区,此时test1类在当前的static代码块执行
    *  6. 创建子类对象之前先创建父类对象,所以先执行Base()构造器,再执行test1()构造器
    * */
    
    public class test1 extends Base{  // 子类
        static{
            System.out.println("test static");
        }
        public test1(){
            System.out.println("test constructor");
        }
    
    }
    
    class Base{  // 父类
        static{
            System.out.println("base static");
        }
        public Base(){
            System.out.println("base constructor");
        }
        public static void main(String[] args){
            new test1();
        }
    }
    

    例2

    /**
     * 流程:
     * 扫描---> 编译 ---> 执行
     * 1. 扫描main()方法所在的Test3类,发现没有父类,开始编译,编译过程中发现有static修饰的代码,按顺序执行static修饰的代码
     * 2. 执行private static int a; 在方法区的静态常量池中开辟内存存储a = 0
     * 3. 将modify()方法入栈,并创建局部变量int a = 0
     * 4. 回到main()方法开始执行modify方法,将a++赋值给局部变量int a,此时局部变量a的值为1
     * 5. modify()方法出栈,此时静态常量池中的a值仍为0
     * 5. 执行System.out.println(a); 输出0
     */
    public class Test3 {
        private static int a;
    
        public static void main(String[] args) {
            modify(a);
            System.out.println(a);
        }
    
        public static int modify(int a){ // 局部变量,只在方法内部起作用
                                         // java只进行值传递
            return a++; // 0
        }
    }
    

    最终modify()方法出栈,将局部变量a干掉,并且因为java语言只进行值传递,并不会将局部变量a传递给方法区中的a,所以最终在输出的时候,a的值仍旧为0

    在这里插入图片描述

    例3

    /**
     * 扫描---> 编译---> 运行
     * 1. main()方法在哪首先扫描哪个类---> 首先扫描Test类,发现没有父类,也没有static修饰的代码,那么编译当前Test类,并且将main()方法入栈
     * 2. 执行new Test4("---");,执行之前扫描Test4类,发现没有父类,所以编译Test4类,在编译过程中发现有static代码按顺序执行
     * 3. 首先输出的是11
     * 4. 执行 public static Test4 test = new Test4("+++"); 此时会设计到调用Test4构造器,所以输出 ===+++
     * 5. 输出22
     * 6. 编译完毕,回到main()方法中继续执行new Test4,现在可以创建对象了!!进入运行阶段
     * 7. 通过调用构造器,创建对象,输出 ===---
     */
    public class Test4 {
        public Test4(String aa){
            System.out.println("==="+aa);
        }
        static {
            System.out.println("11");
        }
        public static Test4 test = new Test4("+++");
        static {
            System.out.println("22");
        }
    }
    
    class Test{
        public static void main(String[] args) {
            Test4 test = new Test4("---");
        }
    }
    

    其中Test4并不会被放在静态常量池中而是作为类信息储存在方法区,其中如果有static修饰的值或者是静态方法的话,会被存储在静态常量池
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值