往者不可谏 来者犹可追

static关键字

Static初步

定义

1、static翻译为“静态的”;
2、所有static修饰的,都是和类相关的,类级别的;
3、所有static修饰的,都是采用“类名.”的方式访问;
4、static修饰的变量---静态变量;
5、static修饰的方法---静态方法;

变量分类

方法区中存---静态变量(类级别)。静态变量在类加载时初始化。
堆中存---实例变量
栈中存---局部变量

变量根据声明的位置划分:
在方法体中声明的变量---局部变量
在方法体外,类中声明的变量---成员变量

成员变量又可以分为:
实例变量---要先有对象(实例),才能有实例变量
静态变量

class VarTest{

    以下实例的,都是对象相关的,访问时采用‘引用.’的方式访问,需要先new对象。
    必须先有对象才能访问,可能会发生空指针异常。
    //成员变量中的实例变量
    int i;
    //实例方法
    public void m(){}
    
    以下静态的,都是类相关的,访问时采用‘类名.’的方式访问,不需要new对象。
    不需要对象的参与即可访问,不会发生空指针异常。
    //成员变量中的静态变量
    static int k;
    //静态方法
    public static void m1(){}
    
    }

什么时候使用静态变量

Q:什么时候变量声明为实例的,什么时候声明为静态的?
A:如果这个类型的所有对象的属性值都是一样的,不建议定义为实例变量,浪费内存空间。
建议定义为类级别特征,即定义为静态变量,在方法区中只保留一句,节省内存开销。
(一个对象一份就是实例变量,所有对象一份就是静态变量)

实例做法:

 public class StaticTest02 {
     public static void main(String[] args) {
         Chinese c1 = new Chinese("1234", "张三", "中国");
        Chinese c2 = new Chinese("12345", "李四 ", "中国");
        System.out.println(c1.idCard);
        System.out.println(c1.name);
        System.out.println(c1.country);
        System.out.println(c2.idCard);
        System.out.println(c2.name);
        System.out.println(c2.country);
   }
  }
      //定义一个类---中国人
      class Chinese{
          String idCard;
          //一个对象一份,每个人身份证号不同,所以应该是实例变量
         String name; //一个人一个姓名,也应该是实例变量。要先有对象才能有实例变量
         String country; //对于中国人这个类来说,国籍都是中国,不会随着对象的改变而改变,属于整个类的特征
 
          public Chinese(){
 
        }
         public Chinese(String s1,String s2,String s3){
              idCard = s1;
              name = s2;
              country = s3;
 
 
          }
     }

静态做法(静态变量要赋值,否则会输出为null!!!)

public class StaticTest02 {
    public static void main(String[] args) {
        System.out.println(Chinese.country);
        Chinese c1 = new Chinese("1234", "张三");
        Chinese c2 = new Chinese("12345", "李四 ");
        System.out.println(c1.idCard);
        System.out.println(c1.name);
        //System.out.println(c1.country);
        System.out.println(c2.idCard);
        System.out.println(c2.name);
       // System.out.println(c2.country);
    }
}
//定义一个类---中国人
class Chinese{
    String idCard;  //一个对象一份,每个人身份证号不同,所以应该是实例变量
    String name; //一个人一个姓名,也应该是实例变量。要先有对象才能有实例变量

    //重点: 加static的变量叫做静态变量。
    //静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了。
    //静态变量存储在方法区,有默认值
    static String country = "中国"; //对于中国人这个类来说,国籍都是中国,不会随着对象的改变而改变,属于整个类的特征

    public Chinese(){

    }
    public Chinese(String s1,String s2){
        idCard = s1;
        name = s2;
    }
}

空指针异常

实例的---一定要用“引用.”来访问;
静态的---建议使用“类名.”来访问,但使用“引用.”也可以。(不建议使用“引用.”)

结论:
空指针异常--只有在“空引用”访问“实例”相关的,都会出现空指针异常。

public class StaticTest03 {
    public static void main(String[] args) {
        //通过"类名."的方式访问静态变量
        System.out.println(Chinese.country);
        //创建对象
        Chinese c1 = new Chinese("111", "小明");
        System.out.println(c1.idCard);
        System.out.println(c1.name);

        //c1是空引用,
        c1 = null;
        //分析这里会不会出现空指针异常?
        //不会
        //因为静态变量不需要对象的存在,通过类名调用即可
        //实际上以下的代码在运行的时候还是把赋空的c1看成 Chinese,依然是通过类名去访问。
        System.out.println(c1.country);

        //这里出现空指针异常,因为name是实例变量,需要对象调用
        //System.out.println(c1.name);
    }
}

    class Chinese01{

        String idCard;
        String name;

        static String country = "中国";

        public Chinese01(String x,String y){
            idCard = x;
            name = y;

        }
    }

带有Static的方法,要通过‘类名.’的方式访问

对象被称为实例,
实例相关的有:实例变量,实例方法,
实例变量是对象变量,实例方法是对象方法。
实例相关的都需要先 ‘new 对象’,通过‘引用.’的方式去访问

public class MethodTest {
    public static void main(String[] args) {
        //在同一个类中,’类名.‘可以省略不写
        MethodTest.dosome();
        dosome();
    //调用没有static的方法
    //创建对象
    MethodTest mt = new MethodTest();
    //通过’引用.‘的方式访问实例方法
    mt.doother();
}

//带有static
public static void dosome() {
    System.out.println("do some!");

}

//这个方法没有static,这样的方法被称为----实例方法。(对象方法,对象级别的方法)。要通过对象的方式访问。
public void doother(){
    System.out.println("do other!");
}

}

空指针异常导致的最本质原因是什么?

空引用访问“实例相关的数据”,会出现空指针异常
实例相关的包括:实例变量(属性) + 实例方法

关于方法来说,什么时候定义为实例方法?

A:此方法一般都是描述了一个行为,如果说该行为必须由对象去出发,那么该方法定义为实例方法。
参考标准:
当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。
以后开发中,大部分情况下,工具类当中的方法一般都是静态方法。(静态方法有一个优点,就是不需要new对象,直接采用类名调用,极其方便。工具类就是为了方便,所以工具类中的方法一般都是静态的。)

使用static关键字可以定义:静态代码块

Q:什么是静态代码块?语法是什么?
A:静态代码块用于初始化类,为类的属性初始化

static{
    java语句;
    java语句;
}

Q:static静态代码块在什么时候执行?
A:类加载时执行,并且只执行一次

静态代码块有这样的特征

注意:
静态代码块在类加载时执行,并且在main方法执行之前执行。
(主方法执行了,类就加载了)
静态代码块一般按照自上而下的顺序执行。

public class StaticTest04 {

    //静态代码块
    static{
        System.out.println("A");
    }
    //一个类中可以编写多个静态代码块
    static{
        System.out.println("b");
    }
    //程序入口
    public static void main(String[] args) {
        System.out.println("hello world");
    }
    //编写一个静态代码块
    static{
        System.out.println("c");
    }
}

Q:静态代码块的作用?
A:第一,静态代码块不常用,不是每一个类都要写
第二,举例;所有编写的程序中,只要是类加载了,请记录一下类加载的日志信息。(在哪年哪月哪日,哪个类加载到JVM中?)
这些记录日志的代码,就应该写在静态代码块中。

静态代码块是一个特殊的时机---类加载时机

代码执行顺序

public class StaticTest05 {
    //静态变量在什么时候初始化?---类加载时
    //静态变量存储在哪里?---方法区
    static int i = 100;

    //静态代码块什么时候执行?---类加载时执行,存储在方法区
    //只要是代码,一定存储在方法区
    static{
        //这里可以访问 i 吗?--- 可以,因为静态的东西在同一时间点完成。
        System.out.println("i=" + i);
    }
     
    //实例变量
    int k = 111; //k变量是实例变量,在new对象的时候才会初始化,在构造方法执行时,内存空间才会开辟
    //这里可以访问 k 变量吗?--- 不可以。静态代码块在类加载时执行,并且只执行一次,类加载时K变量还没开辟出空间(K还不存在)。
    static{
        System.out.println("k");
    }
    
    //静态变量在静态代码块下面,这里可以访问name吗? --- 不可以
    //静态代码块和静态变量都是在类加载的时候执行,时间相同,只能靠代码的顺序来决定谁先谁后。
    static{
        System.out.println("name=" + name);
    }
    static String name = "张三";
    
    //程序入口,实际上在main方法执行之前,已经执行了很多代码。
    public static void main(String[] args) {
        System.out.println("main begin");
    }
}

执行顺序总结

到目前为止,你遇到的所有java程序,有顺序的是哪些?

1、对于一个方法来说,方法体中的代码是有顺序的---自上而下;
2、静态代码块1和静态代码块2是有先后顺序的;
3、静态代码块和静态变量是有先后顺序的;
变量在前,代码块在后。
4、在一个类体中,方法是没有先后顺序的。

实例语句块

1、在类加载时不执行,在构造方法执行之前执行
2、语法

{
    java语句;
    java语句;
}

3、只要是构造方法执行,必然在构造方法之前,执行‘实例语句块’中的代码。--- 对象构建时机
4、可以执行多次,只要调一次构造方法,实例语句块就执行一次。
5、什么时候用?
当有多个构造方法,且每个构造方法的部分代码都一样时,就可以把这段相同的代码放在实例语句块里。这样每次构造方法执行之前,都会执行这段代码。

posted @   你说你叫果郡王  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示