static关键字浅析

本文详细探讨了Java中的static关键字,从初体验和再体验两方面阐述了static修饰的字段和方法的特点。static字段在所有类实例间共享,而static方法只能访问静态字段和静态方法。理解这一特性对于掌握Java类和对象的概念至关重要。
摘要由CSDN通过智能技术生成


在介绍 static关键字之前,我们先考虑两个问题:
1. 如果只为特定域分配存储空间,而不创建对象,应该怎么解决。
2. 如果不创建对象,也能调用对象内的方法,应该怎么解决。

我们在使用Java进行编码时,如果要获得一个对象,那么就要通过new关键字来创建对象,这时数据存储空间才被分配,对象内的方法才可以被外界调用。

如果希望解决文章开头提出的两个问题,应该怎么办呢?
答:通过static关键字就可以解决以上两个问题。

那么为什么通过static关键字就可以解决以上两个问题呢,我们慢慢来分析。


一、static初体验

在解释static为什么会解决以上两个问题之前,我们先来体验下static

  1. 假如有一个类TestStatic,其中有个用static关键字修饰的字段numStatic,给其赋一个初始值为520,还有一个没有用static关键字修饰的字段numNoStatic,给它赋一个初始值为1024
public class TestStatic {
    static int numStatic = 520;
    int numNoStatic = 1024;
}
  1. 现在我们实例化两个TestStatic对象,分别为testStatic1testStatic1
    如果对testStatic2.numStatic执行++操作,即testStatic2.numStatic++;,众所周知,testStatic2.numStatic的值会变成521,那么问题来了,testStatic1.numStatic的值是多少,保持520不变,还是变成521
    废话少说,上代码:
TestStatic testStatic1=new TestStatic();
TestStatic testStatic2=new TestStatic();

System.out.println(testStatic1.numStatic);
System.out.println(testStatic2.numStatic);
testStatic2.numStatic++;
System.out.println(testStatic1.numStatic);
System.out.println(testStatic2.numStatic);

结果为:

520
520
521
521

从打印的结果来看,static修饰的变量和对象无关

  1. 如果对没有被static修饰的变量进行操作,会对其值产生什么影响呢?
    我们对testStatic2.numNoStatic执行++操作,即testStatic2.numNoStatic++;,然后打印testStatic1.numNoStatictestStatic2.numNoStatic的值。
System.out.println(testStatic1.numNoStatic);
System.out.println(testStatic2.numNoStatic);
testStatic2.numNoStatic++;
System.out.println(testStatic1.numNoStatic);
System.out.println(testStatic2.numNoStatic);

结果为:

1024
1024
1024
1025

可以看到,对testStatic2对象中numNoStatic的值进行修改,不会影响到testStatic1对象中numNoStatic的值。
那么也就是说:未被static修饰的变量和对象有关


二、static再体验

  1. 在类TestStatic中,添加两个方法,一个是用static关键字修饰的静态方法add(),另一个是没有用static关键字修饰的非静态方法sub()
public static void add(){
        System.out.println(numStatic++);
        System.out.println(numNoStatic++);//会报错,提示“非静态字段不能被静态上下文引用”
}

public void sub(){
        System.out.println(numStatic--);
        System.out.println(numNoStatic--);
}

可以看到:静态方法中可以使用静态字段,但是不可以使用非静态字段;非静态方法中可以使用静态字段,也可以使用非静态字段

  1. 那么静态方法可以调用静态方法或非静态方法吗,还有,非静态方法可以调用静态方法或非静态方法吗?继续上代码。其中useAddOrSubByStatic()方法是静态方法,useAddOrSub()方法是非静态方法。
public static void useAddOrSubByStatic(){
        add();
        sub();//会报错,提示“非静态方法不能被静态方法引用”
}

public void useAddOrSub(){
        add();
        sub();
}

可以看到:静态方法可以调用静态方法,但是不可以调用非静态方法;非静态方法可以调用静态方法和非静态方法


三、为什么会这样

通过static初体验static再体验后,我们发现了一些奇怪的现象:

  1. static关键字修饰过的字段(静态字段),不管所在类被实例成几个对象,该字段的值只有一个,或者说这些对象的静态字段都指向了同一个存储空间;而那些未被static关键字修饰过的字段(非静态字段),每个实例化的对象都有唯一的字段,或者说每个对象的非静态字段都有自己的存储空间。
  2. static关键字修饰过的方法(静态方法),只可以使用被static关键字修饰过的字段(静态字段),而不能使用未被static关键字修饰过的字段(非静态字段),只可以调用被static关键字修饰过的方法(静态方法),而不能使用未被static关键字修饰过的方法(非静态方法);普通的方法则没有这些问题。

为什么加了static关键字后,不管是字段还是方法都变得“另类”了呢?

在解释staitc为什么会有这种功效之前,我们需要先明确一个概念,那就是:static对每个类来说只有一份存储空间,而非static对每个对象都有一个存储空间。这句话听起来挺拗口的,不过不要紧,让我们来解释下。

Java虚拟机在执行Java程序时,会把它管理的内存划分为若干不同的数据区,包括:方法区、栈、堆、程序计数器等数据区,其中我们只要关注方法区、栈、堆这三个主要的数据区即可。

tips:栈(存放方法执行的参数,如局部变量、方法出口等),堆(存放创建好的对象和数组),方法区(存放被加载的类信息、常量、静态变量、编译后的代码等)

  1. 当虚拟机编译代码完成后,会将编译后的代码、静态变量、静态方法、常量等加载到方法区中;
    加载到方法区

  2. 当通过new创建一个对象时,会在栈中创建一个当前对象的栈帧,并且在堆中会开辟一块内存,加载当前对象的信息;
    创建对象

  3. 当调用静态方法add()时,方法内会用到静态变量numStatic和非静态变量numNoStatic,找静态变量numStatic非常容易,因为add()方法和numStatic变量都在方法区中,但是找numNoStatic变量却找不到了,因为numNoStatic变量在堆的一个对象块中;
    静态方法使用静态及非静态变量

  4. 当调用非静态方法sub()时,方法同样会用到静态变量numStatic和非静态变量numNoStaticsub()方法可以找到非静态变量numNoStatic非常容易,因为它们都在堆的同一个对象块中,sub()方法去找方法区中的静态变量numStatic也同样可以找到(因为方法区存储的就是类的信息);
    非静态方法使用静态及非静态变量

  5. 静态方法调用非静态方法时和步骤3类似,也是因为在方法区中的静态方法useAddOrSubByStatic()找不到在堆中对象块中的非静态方法sub()
    非静态方法useAddOrsub()则可以调用同属于堆中对象块中的非静态方法sub(),也可以调用方法区中的静态方法add()
    静态方法及非静态方法的互调


四、结尾

通过以上的分析,我们可以总结出以下内容:
当声明一个变量、方法、代码块等事物为static时,就意味着这个事物不会与所在类的实例对象有关联。也就是说,即使从未创建某个类的对象,也可以调用其中的static关键字修饰的事物。同样的,不管对同一个类创建了多少个不同的实例对象,其中用static关键字修饰的事物也只有一个(一个存储空间)。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值