【Java SE】深入理解static关键字

🥰🥰🥰来都来了,不妨点个关注叭!
👉博客主页:欢迎各位大佬!👈

在这里插入图片描述

1.static关键字

1.1 static的概念

【概念】:static表示"全局"/"静态"的含义,但是Java语言中没有全局变量的概念,因此在Java中用static来修饰方法/变量等,称为静态成员方法/静态成员变量,也可以形成静态static代码块。
【特点】
被static修饰的成员变量/成员方法不依赖该类的任何对象,即它不依赖类特定的实例,被类的所有实例共享,静态的成员不属于对象,通过类名进行访问
【为什么】
因为只要这个类被加载,Java虚拟机可以根据类名在运行时数据区的方法区内找到它们,因此,可以在它的任何对象创建之前访问,无需引用任何对象。
【注意】
1)非静态成员变量/方法从属于对象
2)静态成员变量/方法从属于类

1.2 static的作用

现在有Student类,实例化六个对象,分别为student1 、student2、student3、student4 、student5和student6,每个对象都有自己特有的学号、性别、成绩、姓名等信息,代码如下:

public class Student {
    private int sno;//学号
    public String sex;//性别
    public int score;//分数
    public String name;//姓名

     public Student(int sno, String sex, int score, String name) {
        this.sno = sno;
        this.sex = sex;
        this.score = score;
        this.name = name;
    }
}

class Test {
    public static void main(String[] args) {
        Student student1  = new Student(1,"女",98,"张三");
        Student student2  = new Student(2,"男",90,"李四");
        Student student3  = new Student(3,"男",88,"小丁");
        Student student4  = new Student(4,"女",99,"小万");
        Student student5  = new Student(5,"女",80,"小晚");
        Student student6  = new Student(6,"男",77,"小新");
    }
}

在这里插入图片描述
假设这六名同学为同一个班的, 故他们也在同一间教室上课,如何表示?
如果在Student类中再加一个成员变量classRoom,用来保存教室,这样的方案是否可行?
在回答这些问题之前,我们先来想一想,如果这样做的话,每一个对象都会包含classRoom这一份实例变量,用这些信息来具体描述每一个学生。但是我们清楚地知道,并不需要每实例化一个对象,都保存着这个教室成员变量classRoom,这六个对象都在这个教室,需要他们来共享这个变量。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,并不属于某个具体的对象,是所有对象所共享的。
简而言之:在不用创建对象的情况下,调用类的方法/变量,是可以共享的

1.3 static的用法

1.3.1 static修饰成员变量

在Java中,static修饰的成员变量,称为静态成员变量
【静态成员变量特性】
1)不属于某个具体的对象,是类的属性,所有对象共享,不存储在某个对象的空间中,类变量存储在方法区当中
2)可以通过类名访问,也可以通过对象访问,一般更推荐使用类名访问(毕竟都使用static啦,那就使用其特有的属性)
3)生命周期伴随类的一生,即随类的加载而创建,随类的卸载而销毁
上述问题的解决代码:

public class Student {
    private int sno;//学号
    public String sex;//性别
    public int score;//分数
    public String name;//姓名
    
    public static String classRoom = "L1210";
}

class Test {
    public static void main(String[] args) {
        System.out.println(Student.classRoom);
    }
}

打印结果如下:
在这里插入图片描述
可以清楚看到,静态成员变量并未存储到某一个对象中,存在方法区当中,供所有对象共享
在这里插入图片描述

1.3.2 static修饰成员方法

在Java中,被static修饰的成员方法称为静态成员方法/类方法
【静态成员方法特性】
1)不属于某个具体的对象,是类方法
2)可以通过类名访问,也可以通过对象访问,一般更推荐使用类名访问
3)对于静态成员变量,不能在非静态方法中访问任何静态成员变量
举个例子:test1为非静态方法,age为静态变量,test1无法访问age变量

public void test1() {
static int age = 12;
}

在这里插入图片描述
4)对于静态成员方法,非静态方法中不能调用任何静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用,即通俗记忆非静态不能访问静态,但是静态的方法内部可以访问非静态数据等,但不是能够直接使用非静态,必须依赖对象。所以这也是为什么main方法是static修饰的静态方法,既可以访问静态成员变量调用静态成员方法,也可以访问非静态成员变量调用非静态成员方法
举个例子:test2不是静态方法,test1是静态方法,所以test1不能调用test2这个非静态方法

class Test {
    public static void main(String[] args) {
        test2();
    }

    public static void test1() {
        System.out.println("!!!");
    }

    public void test2() {
        test1();
    }

在这里插入图片描述
4)静态方法无法重写,不能用来实现多态
总结
1)非静态成员方法不能访问静态成员变量和调用静态成员方法
2)静态成员方法可以访问非静态成员变量和调用静态成员方法,但不是直接的,依赖于对象

1.3.3 static修饰成员变量初始化

1)直接初始化
在定义时直接给出初始值(如下面这段代码classRoom是静态成员变量,在定义时候直接初始化)

public static String classRoom = "L1210";

2)默认初始化
3)通过get和set方法进行初始化

public class Student {
    private int sno;//学号
    public String sex;//性别
    public int score;//分数
    public String name;//姓名
    public static String classRoom ;
    
    public static String getClassRoom() {
        return classRoom;
    }
    
    public static void setClassRoom(String classRoom) {
        Student.classRoom = classRoom;
    }
}

注意】需要在get和set方法前加static,因为classRoom是静态成员变量,只能在静态方法中访问
4)构造对象时,构造方法中赋值(不推荐使用)

public class Student {
    private int sno;//学号
    public String sex;//性别
    public int score;//分数
    public String name;//姓名

    public static String classRoom ;

    public Student(int sno, String sex, int score, String name, String a) {
        this.sno = sno;
        this.sex = sex;
        this.score = score;
        this.name = name;
        classRoom = a;
    }
}

注意】这是构造方法,不要加任何修饰符如void之类的,可以加访问修饰限定符如public等
5)代码块初始化(使用较少)

【注意】
静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性,而静态成员变量不需要实例化对象来访问

2. 代码块

概念】使用 {}(一对大括号) 定义的一段代码称为代码块
分类】根据代码块定义的位置以及关键字,可分为以下四种:普通代码块、构造代码块、静态代码块和同步代码块

2.1 普通代码块

定义:方法内的代码块
在这里插入图片描述

2.2 构造代码块(实例代码块、非静态代码块)

定义:类内,方法外的代码块
作用:构造代码块一般用于初始化实例成员变量

public class Student {
    private int sno;//学号
    public String sex;//性别
    public int score;//分数
    public String name;//姓名

    public Student(int sno, String sex, int score, String name) {
        this.sno = sno;
        this.sex = sex;
        this.score = score;
        this.name = name;
        System.out.println("我是构造方法~");
    }

    {
        System.out.println("构造代码块/实例化代码块/非静态代码块");
    }
}

class Test {
    public static void main(String[] args) {
        Student s1 = new Student(123,"女",99,"小小");
    }
}

得到结果如下:
在这里插入图片描述
从结果我们可以看到,先打印的构造代码块里的内容,后打印构造方法里的内容,而不是看顺序打印
可以简单认为:编译器会把非静态代码块的东西放在构造方法的最前面

2.3 静态代码块

定义:使用static修饰的代码块
作用:初始化静态成员数据以及提前准备一些数据

 static {
    classRoom = "L1210";
    System.out.println("静态代码块");
 }

注意
1)静态代码块只执行1次,无论生成多少个对象,类被加载就执行
2)实例化代码块依赖于对象,只有实例化对象时才会执行
3)一个类中包含多个静态代码块,编译器按照定义的先后执行

2.4 同步代码块

涉及到多线程

3. 内部类

内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类。

3.1 实例内部类

定义:未被static修饰的内部成员

public class Outclass {
    private String a;
    static int b;
    int c;
    public void method(){
        a = "hh";
        System.out.println(a);
    }
    // 实例内部类
    class Innerclass{
        int c;
        public void methodInner(){
            // 在实例内部类中可以直接访问外部类任意!!!外部类abc变量的修饰符都不同,任意访问!
            b = 666;
            method();
            a = "lala";
            System.out.println(a);
            // 如果外部类和实例内部类中具有相同名称成员时,优先访问内部类自己的成员
            c = 999;
            System.out.println(c);
            // 如果要访问外部类同名成员时候:外部类名称.this.同名成员名字
            Outclass.this.c = 300;
            System.out.println(Outclass.this.c);
        }
    }
    public static void main(String[] args) {
        System.out.println("有关实外部类的访问");
        // 外部类:对象创建以及成员访问
        Outclass outclass = new Outclass();
        System.out.println(outclass.a);
        System.out.println(Outclass.b);
        System.out.println(outclass.c);
        outclass.method();
        System.out.println("有关实例内部类的访问");
        // 1.要访问实例内部类中成员,必须要创建实例内部类的对象
        // 2.创建实例内部类对象时必须借助外部类
        // 3,创建实例内部类对象 依赖外部类的对象
        //方法1:
        Outclass.Innerclass innerClass1 = new Outclass().new Innerclass();
        // 上述语法比较麻烦,也可以先将外部类对象先创建出来,然后再创建实例内部类对象
        //方法2:
        Outclass.Innerclass innerclass2 = outclass.new Innerclass();
        innerclass2.methodInner();
    }
}

注意
1)在实例内部类方法中可以直接访问外部类中的任何成员
2)外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象
3)实例内部类受public、private等访问限定符的约束
4)在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,需要:

外部类名称.this.同名成员 来访问

5)实例内部类对象必须在先有外部类对象前提下才能创建
6)实例内部类的非静态方法中包含一个指向外部类对象的引用

3.2 静态内部类

定义:被static修饰的内部成员

public class Outclass {
    private String a;
    static int b;
    int c;
    public void method1(){
        a = "hh";
        System.out.println(a);
    }

    public static void method2(){
        System.out.println(b);
    }

    // 静态内部类
    static class Innerclass{
        int c;
        public void methodInner(){
            // a = "lala";
            // c = 20;
            //编译失败 静态内部类中只能访问外部类的静态成员变量 a、b变量不是静态变量
            b = 100; //b可以访问,因为b被static修饰,是静态变量
            //method1();
            //编译失败 静态内部类中只能访问外部类的静态成员方法 method1不是静态方法
            method2();
        }
    }
    public static void main(String[] args) {

        //直接用外部类
        Outclass.Innerclass innerClass = new Outclass.Innerclass();
        innerClass.methodInner();
    }
}

注意
1)静态内部类中只能访问外部类中的静态成员
2)创建静态内部类对象时,不需要先创建外部类对象,因为静态不依赖对象

3.3 局部内部类

定义:外部类的方法体或者{}
局部内部类只能在其定义的位置使用,一般使用非常少

public class Outclass {
    public String a;
    // 局部内部类(在这个方法体中)
    public void method() {
    class Innerclass {
        public void methodInner() {
            System.out.println(a);
        }
    }
        Innerclass innerclass = new Innerclass();
        innerclass.methodInner();
    }
}

注意
1) 局部内部类只能在所定义的方法体内部使用
2)不能被修饰符修饰,如public、static等修饰符

3.4 匿名内部类

涉及到抽象类和接口
本期内容回顾~
在这里插入图片描述
下期再见!一起加油呀~

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值