JavaSE语法(7)——详细解读Java中的static关键字和代码块

目录

前言

✏️static关键字

1.static修饰成员变量

1.1 调用static修饰的成员变量

2. static修饰成员方法

3.static修饰的成员在内存中的位置

✏️代码块

1.普通代码块

2.构造代码块

3.静态代码块


前言

         我的JavaSE语法专栏地址,可以看看哦,可能你会有不一样的收获。JavaSE_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/che__dan/category_11970438.html?spm=1001.2014.3001.5482​​​​​​​​​​​​​​


JavaSE语法(6)——【类和对象(类的内存模型、访问限定符public、private等、包的导入……)】_虾料的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127669373?spm=1001.2014.3001.5501        上一篇文章中static关键字还没有介绍,不过放心,本篇给大家介绍清楚。



✏️static关键字

        在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。


1.static修饰成员变量

        static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。

        咱们先来看看案例:假如你是2022年级5班的一名同学。现在你有班级、姓名、性别、年龄这四种属性,同时你的同学也有这四种属性。我们是否就可以定义一个这样的类:

public class Student {
    String s_class;
    String name;
    String sex;
    int age;

    public Student(){

    }
    public Student(String s_class, String name, String sex, int age) {
        this.s_class = s_class;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public void print(){
        System.out.println("s_class: " + s_class + "name: " + name + " sex: " + sex + " age: " + age);
    }
}

        每一个同学的信息都可以实例化一个对象来表示。但是如果5班有60位同学,那么我们就需要对s_class赋值50次,且每次都是同一个值。那么我们这么解决这个问题?

        我们可以把s_class变为一个静态的s_class:

public class Student {
    static String s_class;
    String name;
    String sex;
    int age;

    public Student(){

    }
    public Student(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public void print(){
        System.out.println("s_class: " + s_class + "  name: " + name + "  sex: " + sex + "  age: " + age);
    }
}

        我们实例化几个对象,并对s_class进行赋值:

public class Main{
    public static void main(String[] args) {
        
        Student.s_class = "5班";
        Student s = new Student("小明","男",19);
        Student s2 = new Student("小花","男",20);
        Student s3 = new Student("李四","男",21);
        Student s4 = new Student("张三","男",20);

        s.print();
        s2.print();
        s3.print();
        s4.print();
    }
}

 结果:

s_class: 5班  name: 小明  sex: 男  age: 19
s_class: 5班  name: 小花  sex: 男  age: 20
s_class: 5班  name: 李四  sex: 男  age: 21
s_class: 5班  name: 张三  sex: 男  age: 20

        这里的5班是这个类的属性,是每个实例对象所共有的,当s_class被修改了一次,那么对所有该类的对象都生效。

        上面的“Student.s_class”是什么意思呢?其实就是调用这个变量,具体的在。

1.1 调用static修饰的成员变量

        static变量可以通过对象访问也可以通过类名访问,但一般更推荐使用类名访问。

  • 通过类名访问
pubic class Main{
    public static void main(String[] args) {

        //通过类名访问并修改
        Student.s_class = "5班";

        Student s = new Student("小明","男",19);
        Student s2 = new Student("小花","男",20);
        Student s3 = new Student("李四","男",21);
        Student s4 = new Student("张三","男",20);
        s.print();
        s2.print();
        s3.print();
        s4.print();
    }
}
  • 通过对象访问
class Main{
    public static void main(String[] args) {

        //通过对象访问并修改
        Student s = new Student("小明","男",19);
        s.s_class = "5班";

        Student s2 = new Student("小花","男",20);
        Student s3 = new Student("李四","男",21);
        Student s4 = new Student("张三","男",20);
        s.print();
        s2.print();
        s3.print();
        s4.print();
    }
}

以上都是同一个结果。

s_class: 5班  name: 小明  sex: 男  age: 19
s_class: 5班  name: 小花  sex: 男  age: 20
s_class: 5班  name: 李四  sex: 男  age: 21
s_class: 5班  name: 张三  sex: 男  age: 20

 总结:

  • 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中。
  • 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问。
  • 类变量存储在方法区当中(具体的在文章后面)。

  • 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)。
public class Student {
    static String s_class = "5班";
    //........
    //.......
    //.....
}

class Main{
    

    public static void main(String[] args) {
    //生命周期开始
        System.out.println(Student.s_class);

    }
    //生命周期结束
}

结果:5班


2. static修饰成员方法

        同样的道理,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的,其调用方法也是通过类名来调用(当然也可以用具体的对象来调用)。
        比如:

public class MyMath {
    public static int add(int a,int b){
        return a + b;
    }
}

///
public class Main3{
    public static void main(String[] args) {
        int c = 10;
        int d = 50;
        
        //用类名访问
        int sum = MyMath.add(c,d);
        System.out.println(sum);

        //用对象访问
        MyMath math = new MyMath();
        int sum2 = math.add(c,d);
        System.out.println(sum2);
    }
}


结果:
60
60

总结:

  • static方法不属于某一个具体的对象,而是类方法,是类本身所拥有的。
  • 可以通过对象调用,也可以通过 类名调用,更推荐使用后者。

  • 不能在静态方法中调用任何的非静态成员变量。

        原因很好理解:静态方法是属于整个类的,当class文件加载后就已经存在了;非静态变量要在进行实例化的时候才会创建,已经创建的方法引用未创建的变量,这当然不行。

JavaSE语法(7)——详细解读Java中的static关键字和代码块_第1张图片

  • 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用。

JavaSE语法(6)——【类和对象(类的内存模型、访问限定符public、private等、包的导入……)】_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127669373?spm=1001.2014.3001.5502        在上面的文章中提过在非静态方法中有一个隐藏的参数,this引用,它是方法的第一个参数。

        在静态方法中调用非静态方法时候,对于非静态方法我们肯定得要传入相应的this参数(非静态方法的第一个参数),然而事实是静态方法中无法传入this引用,所以我们无法对非静态方法进行传参。

JavaSE语法(7)——详细解读Java中的static关键字和代码块_第2张图片        


       static方法还有一种用法:我们知道对类的属性进行封装时需要用private修饰符,并且需要相应的get与set方法来修改被封装的属性的值,如下:

public class Student {
    private static String s_class;
    private String name;
    private String sex;
    private int age;
    
    //获取s_class
    public static String getS_class() {
        return s_class;
    }
    //修改 s_class
    public static void setS_class(String s_class) {
        Student.s_class = s_class;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }


    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }


    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

}

        对于s_class字段我们不能用普通方法来对其操作,要用static方法才行。


3.static修饰的成员在内存中的位置

        类信息是装在方法区里,类信息又分为静态与非静态区。具体如下:

public class Cat{
    public String name;
    public String color;
    //猫的叫声
    public void meow() {
        System.out.println(color + "的" + name + ":喵喵喵~");
    }
    //.......

    
    //特征
    public static String trait = "有四条腿";
    //习性
    public static void habits(){
        System.out.println("喜欢吃鱼");
    }
}

///
public class Main{
    public static void main(String[] args) {
        Cat c = new Cat();
        c.name = "小白";
        c.color = "白色";
        c.meow();

        System.out.println(Cat.trait);
        Cat.habits();
    }
}

        这个例子在上一篇文章(JavaSE语法(6))中详细介绍过,我们这里只是加了一个静态区。

        static成员随着字节码文件的加载而被加载,当JVM将 Cat.class 加载进内存时静态成员变量就存在了,和字节码一样,位于一块叫做方法区的内存空间中,类成员变量被该类的所有对象所共享。

(ps:注意这里的内存图是jdk1.8之前版本的,之后的版本(包括1.8)静态成员在堆里(静态区在堆里)

JavaSE语法(7)——详细解读Java中的static关键字和代码块_第3张图片

                                                                    (jdk1.8之前)



✏️代码块

        使用{}定义的一段代码称为代码块。代码块有四种:普通代码块、构造块、静态块、同步代码块,同步代码块是一种多线程保护机制。(ps:由于这个知识点涉及到多线程,这儿就不介绍了,留到多线程介绍。)



1.普通代码块

        定义在方法中的代码块叫普通代码块。

public class Main {
    public static void main(String[] args) {

        //普通代码块(在main方法中)
        {
            int x = 250;
            System.out.println("执行普通代码块!x = " + x);
        }
        int x = 100;
        System.out.println("我在普通代码块外面!x = " + x);
    }
}

结果:

执行普通代码块!x = 250
我在普通代码块外面!x = 100

        普通代码块里的变量,只要出了代码块,其生命周期就结束了,所以这里重复定义x没有报错。


2.构造代码块

        在类中定义的代码块叫构造代码块,也叫实例代码块。它作用一般用于初始化类里的成员变量(静态的变量也能初始化,但不推荐)。

public class Student {
    private String name;
    private int age;
    private static String s_class;

    public Student (){
        System.out.println("我是Student的构造方法!!!");

    }

    //构造代码块(实例代码块)
    {
        
        this.name = "张三";
        this.age = 20;
        s_class = "5班";
        System.out.println("我是构造代码块(实例代码块)!!!");
    }

    public void print(){
        System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
    }
}

/

public class Main2{
    public static void main(String[] args) {
        Student student = new Student();
        student.print();
    }
}

 结果:

我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班

         注意这里的执行顺序!这里的执行顺序是实例代码块先于构造方法 执行。


3.静态代码块

        使用static定义的代码块称为静态代码块,一般用于初始化静态成员变量。

public class Student {
    private String name;
    private int age;
    public static String s_class;

    public Student (){
        System.out.println("我是Student的构造方法!!!");
    }

    //静态代码块
    static {
        s_class = "5班";
        System.out.println("我是静态代码块!!!");
    }

    //实例代码块
    {
        this.name = "张三";
        this.age = 20;
        System.out.println("我是构造代码块(实例代码块)!!!");
    }

    public void print(){
        System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
    }
}

/

public class Main2{
    public static void main(String[] args) {
        String str = Student.s_class;
        System.out.println(str);
    }
}

结果:

我是静态代码块!!!
5班
  • 可以看到,静态代码块在没有实例化对象时候也可以运行;而实例代码块只有在创建对象时才会执行。

        那我new一个实例的时候呢?

public class Student {
    private String name;
    private int age;
    public static String s_class;
    
    //构造方法
    public Student (){
        System.out.println("我是Student的构造方法!!!");
    }

    //构造代码块(实例代码块)
    {
        this.name = "张三";
        this.age = 20;
        System.out.println("我是构造代码块(实例代码块)!!!");
    }

    //静态代码块
    static {
        s_class = "5班";
        System.out.println("我是静态代码块!!!");
    }

    public void print(){
        System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
    }
}

/
public class Main2{
    public static void main(String[] args) {
        Student student = new Student();
        student.print();
        System.out.println("#################################");
        Student student2 = new Student();
        student2.print();
    }
}

 结果:

我是静态代码块!!!
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班
#################################
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班
  • 这里有一个很重要的点,即静态代码块在一个程序运行的时候只会执行一次!!!(不管生成多少个对象,静态代码块只会执行一次)
  • 在同一个类中,各种代码块之间的执行顺序是:静态代码块->实例代码块->构造方法。

  • 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)。 
public class Student {
    private String name;
    private int age;
    public static String s_class;

    //构造方法
    public Student (){
        System.out.println("我是Student的构造方法!!!");
    }

    //构造代码块(实例代码块)
    {
        this.name = "张三";
        this.age = 20;
        System.out.println("我是构造代码块(实例代码块)!!!");
    }

    //静态代码块
    static {
        System.out.println("我是静态代码块A!!!");
    }

    static {
        System.out.println("我是静态代码块B!!!");
    }

    static {
        System.out.println("我是静态代码块C!!!");
    }
    
}

/
class Main2{
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println("#################################");
        Student student2 = new Student();

    }
}

 结果:

我是静态代码块A!!!
我是静态代码块B!!!
我是静态代码块C!!!
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
#################################
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!


你可能感兴趣的:(JavaSE,java,开发语言)