欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA学习——Java中static关键字的解析

程序员文章站 2024-03-05 12:24:06
...

在Java中static是很难理解的一个关键字,对于初学者来说很容易混淆,不知道在什么情况下使用static来使用static修饰方法或者变量。本篇文章从以下几个方面对static的使用原理进行分析。
1、static关键字的基本用法
2、深入分析static关键字
3、private static修饰

本篇文章为记录自己的学习过程,若有不正之处,希望谅解并欢迎批评指正。

一、static关键字的基本用法

在使用static修饰变量或者方法之前,需要明白只要使用了static来修饰了变量和方法,那这个修饰的东西不需要创建对象来调用,直接使用类名就可以调用了。

1、static修饰变量
如果一个变量被static关键字修饰了,那么这个变量不再属于自己,而是属于所在的类,即不需要再创建一个对象来调用这个变量,直接使用类名.变量名就可以调用了。static变量可以被所有对象共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。

2、static修饰方法
一旦使用static修饰方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
注意事项:

  1. 静态不能直接访问非静态,
    原因:因为在内存中是【先】有的静态内容,【后】有的非静态内容。静态先执行,后释放。
  2. 静态方法当中不能使用this
    原因:this代表当前对象,通过谁调用的方法,谁就是当前的对象。
public class MyClass {

    static int numStatic; //静态变量
    int num; // 成员变量

    // 静态方法
    public static void methodStatic() {
        System.out.println("我是静态方法!");
        // 静态方法可以访问静态变量

        System.out.println(numStatic);
        // 静态方法不能访问成员变量【】重点
        //System.out.println(num); // 错误写法

        // 静态方法中不能使用this关键字
        //this. // 错误写法
    }

    // 成员方法
    public void method() {
        System.out.println("我是成员方法!");
        // 成员方法可以访问成员变量
        System.out.println(num);

        // 成员方法可以访问静态变量
        System.out.println(numStatic);
    }
}

3、静态代码块
静态代码块的格式是:

public class 类名称{
    static {
        // 静态代码块内容
    }
}

特点:当第一次用到本类时,静态代码块执行的唯一一次
静态内容总是用于非静态,所以静态代码块比构造方法先执行

静态代码块的典型用途:用来一次性地对静态成员变量进行赋值。

public class Person {
    static {
        System.out.println("静态代码块执行!");
    }

    public Person(){
        System.out.println("构造方法执行!");
    }
}
// 输入顺序:静态代码块执行,构造方法执行。

二、深入分析static关键字

从JVM内存来看static修饰的静态区。

常用的3个内存结构:

  1. 栈(Stack):用来存放基础变量以及对象的引用,存放的是具体的数值。
  2. 堆(Heap):new出来的东西都放在堆中,即对象本身,存放的是地址值。
  3. 方法区(Method Area):存放的是.class文件,即代码块,使用static修饰的时候,会在方法区中开辟一块静态区。

从内存的角度来看,为什么static会有这样的特性,首先定义一个Student类。

public class Student {

    private int id;
    private String name;
    private int age;
    static String room;
    private static int idCountter;

    public Student() {
        this.id = ++idCountter;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.id = ++idCountter;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

然后来调用它:

public class Demo3Student {

    public static void main(String[] args) {
        // 首先设置一下教室,这是静态的东西,应该通过类名称进行调用
        Student.room = "3年级2班";

        Student one = new Student("周杰伦",38);
        System.out.println("姓名:" + one.getName() +
                ",年龄" + one.getAge() + ",年纪" + Student.room);
        Student two = new Student("林俊杰",36);
        System.out.println("姓名:" + two.getName() +
                ",年龄" + two.getAge() + ",年纪" + Student.room);
    }
}

接下来我们从内存的角度出发,看看这个程序运行的过程。
JAVA学习——Java中static关键字的解析
从图中可以调用static关键字修饰的变量或者方法的时候是直接从方法区调用的,而对象是存储在堆中的,多个对象共享一份static数据,一变都变。

下面对static关键字进行一个小结:

(1)特点:

1、static是一个修饰符,用于修饰成员。(成员变量,成员函数)static修饰的成员变量 称之为静态变量或类变量。

2、static修饰的成员被所有的对象共享。

3、static优先于对象存在,因为static的成员随着类的加载就已经存在。

4、static修饰的成员多了一种调用方式,可以直接被类名所调用,(类名.静态成员)。

5、static修饰的数据是共享数据,对象中的存储的是特有的数据。

(2)成员变量和静态变量的区别:

1、生命周期的不同:

成员变量随着对象的创建而存在随着对象的回收而释放。

静态变量随着类的加载而存在随着类的消失而消失。

2、调用方式不同:

成员变量只能被对象调用。

静态变量可以被对象调用,也可以用类名调用。(推荐用类名调用)

3、别名不同:

成员变量也称为实例变量。

静态变量称为类变量。

4、数据存储位置不同:

成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。

静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

(3)静态使用时需要注意的事项:

1、静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)

2、静态方法中不可以使用this或者super关键字。

3、主函数是静态的

三、private static修饰

被private static修饰的属性仅仅可以被静态方法调用,但是只能被本类中的方法(可以是非静态的)调用,在外部创建这个类的对象或者直接使用这个类访问都是非法的。

public class MyTest {

    static String name;
    private static int age;

    public static void test(){
        age++;
    }
}

调用:

public class Demo05MyTest {

    public static void main(String[] args) {
        MyTest.name = "李连杰";
        MyTest.age;//错误
        MyTest myTest = new MyTest();
        myTest.age;//错误
    }
}