发布时间:2025-12-10 23:18:38 浏览次数:1
为什么需要static?
有时候我们并不想去new一个对象,只是单纯的想要调用一个函数,并且希望这个函数不会与包含它的类的其他对象有所关联。说得通俗点,即使没有创建对象,也能通过类本身来调用函数。
static静态变量
被static修饰的变量属于类变量,通过字面意思就说明了这个变量的归属(类),与之相对的是没有被static修饰的成员变量,也称为实例变量,说明这个变量是属于某个具体的对象。
publicclassStaticDemo{privatestaticinti=50;privateintj=60;publicstaticvoidmain(String[]args){StaticDemostaticDemo=newStaticDemo();StaticDemostaticDemo1=newStaticDemo();//即使创建两个对象,也都指向同一存储空间System.out.println(staticDemo.i);System.out.println(staticDemo1.i);//改变值staticDemo.i=52;System.out.println(staticDemo1.i);staticDemo.j=65;staticDemo1.j=70;System.out.println(staticDemo.j);System.out.println(staticDemo1.j);}}输出
50
50
52
65
70
通过上面的实例,我们很快看出他们的区别
静态变量是属于类的,只有一份存储空间,是类之间共享的,牵一发而动全身,一处变,处处变。
实例变量属于实例对象,创建几次对象,就有几份的成员变量(拷贝)。
static修饰的静态函数
说到静态函数,就不得不提Java另一个关键词this,指的是当前的引用。意思是调用这个函数的对象,这意味着和static修饰的函数水火不容。被static修饰的函数,不能出现this关键字,否则便会报错。
去掉this,分别调用i或者j,会发现静态函数调用非静态资源时出错。这是为什么?从JVM加载机制角度来说,静态资源(被staitc修饰)是类在初始化的时候就加载的,而非静态资源是new的时候加载的。类的初始化是早于new的,加载了say()的函数时,它并不认识 j 这个成员变量,但对于非静态函数来说,当它加载时,静态资源已经加载完毕,所以它是认识 i 这个静态资源的。我们总结一下static修饰函数时的特点
静态函数不能引用非静态资源;
非静态函数可以引用静态资源;
静态函数可以相互调用(只要引入所在包即可);
静态函数没有this,因为它不依附于任何对象。
现在,我们也能知道main函数为什么必须是static的,因为程序在执行main函数时候,没有创建任何对象,只是通过类名来访问。
构造函数是不是静态函数?
《Java编程思想》提到“即使没有显示地使用static关键字,构造器实际上也是静态方法”。我至今不能确认构造器是不是静态函数,个人更偏向于不是。原因待会再阐述,先看个实例
publicclassStaticTest{privatestaticinti;privateintj;publicStaticTest(inti,intj){this.i=i;this.j=j; say1()}publicvoidsay1(){System.out.println("youageis"+i);System.out.println("youageis"+j);}publicstaticvoidmain(String[]args){StaticTeststaticTest=newStaticTest(4,5);StaticTeststaticTest1=newStaticTest(10,69);System.out.println(staticTest.i);System.out.println(staticTest.j);System.out.println(staticTest1.i);System.out.println(staticTest1.j);}}输出
you age is4
you age is5
you age is10
you age is69
10
5
10
69
实例中,确实改变了 i 的值,也符合静态资源的定义,只有一份存储空间。但构造器里用了this,与我前文所说的static属于类,不属于任何对象,this属于当前引用对象互相矛盾,并且构造函数还可以调用实例函数。一脸懵逼,这也是让我感到困惑并且认为构造函数不是静态函数的地方。如有周知,留言解惑,感谢。
静态块与非静态块
private static int i;
static
{
i = 5;
}
静态块是static的重要应用之一,无函数名、作用域、返回值以及参数,静态代码块与静态变量和静态函数一样,不论类被调用多少次,该区域代码只在类初始化时第一次时执行一次,并且严格按照静态资源的定义顺序执行加载,与静态函数区别在于一个主动一个被动。
{
System.out.println("我是静态块.");
}
非静态块,同样无函数名,作用域,返回值以及参数,非静态代码块会在每次类被调用或者被实例化时执行。
实例
publicclassStaticTestextendsFather{publicStaticTest(){System.out.println("我是StaticTest的构造函数");}{System.out.println("我是StaticTest的非静态块");}static{System.out.println("我是StaticTest的静态块");}publicstaticvoidmain(String[]args){newStaticTest();newStaticTest();}}classFather{publicFather(){System.out.println("我是Father构造函数");}{System.out.println("我是Father非静态块1");}{System.out.println("我是Father非静态块2");}static{System.out.println("我是Father静态块");}}输出
我是Father静态块
我是StaticTest的静态块
我是Father非静态块1
我是Father非静态块2
我是Father构造函数
我是StaticTest的非静态块
我是StaticTest的构造函数
我是Father非静态块1
我是Father非静态块2
我是Father构造函数
我是StaticTest的非静态块
我是StaticTest的构造函数
加载顺序 :父类静态块 > 子类静态块 > 父类非静态块 > 父类构造函数 > 子类非静态块 > 子类构造函数
静态代码块以及非静态代码块都会在构造函数前执行,首次访问时,静态代码块会在非静态代码块前执行。
改变main函数
public static void main(String[] args)
{
}
输出
我是Father静态块
我是StaticTest的静态块
静态代码块在类加载时自动执行,非静态代码块是在创建对象时自动执行的代码,不创建对象不执行该类的非静态代码块。
静态导入
静态导入是jdk5引入的新特性,有时我们在实际应用中,并不需要整个jar包都导入,而只是想使用某部分函数。提高代码的阅读性,更好的理解程序。
importstaticjava.lang.System.out;publicclassStaticTest{publicstaticvoidmain(String[]args){out.println("importstatic测试"); System.out.println("importstatic测试");}}输出
import static测试
import static测试