概述
只要是有学过 Java 的都一定知道 static, 也一定能多多少少说出一些作用和注意事项. 如果已经对 static 了如指掌的请点击关闭按钮, 看下去也只是浪费您宝贵时间而已. 这篇随笔只是个人的习惯总结.
为什么需要 static?
有时候我们并不想去 new 一个对象, 只是单纯的想要调用一个函数, 并且希望这个函数不会与包含它的类的其他对象有所关联. 说得通俗点, 即使没有创建对象, 也能通过类本身来调用函数.
static 静态变量
被 static 修饰的变量属于类变量, 通过字面意思就说明了这个变量的归属(类), 与之相对的是没有被 static 修饰的成员变量, 也称为实例变量, 说明这个变量是属于某个具体的对象.
- public class StaticDemo
- {
- private static int i = 50;
- private int j = 60;
- public static void main(String[] args) {
- StaticDemo staticDemo = new StaticDemo();
- StaticDemo staticDemo1 = new StaticDemo();
- // 即使创建两个对象, 也都指向同一存储空间
- 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 关键字, 构造器实际上也是静态方法". 我至今不能确认构造器是不是静态函数, 个人更偏向于不是. 原因待会再阐述, 先看个实例
- public class StaticTest
- {
- private static int i;
- private int j;
- public StaticTest(int i,int j){
- this.i = i;
- this.j = j;
- say1()
- }
- public void say1()
- {
- System.out.println("you age is" + i);
- System.out.println("you age is" + j);
- }
- public static void main(String[] args)
- {
- StaticTest staticTest = new StaticTest(4,5);
- StaticTest staticTest1 = new StaticTest(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("我是静态块.");
- }
非静态块, 同样无函数名, 作用域, 返回值以及参数, 非静态代码块会在每次类被调用或者被实例化时执行.
实例
- public class StaticTest extends Father
- {
- public StaticTest()
- {
- System.out.println("我是 StaticTest 的构造函数");
- }
- {
- System.out.println("我是 StaticTest 的非静态块");
- }
- static
- {
- System.out.println("我是 StaticTest 的静态块");
- }
- public static void main(String[] args)
- {
- new StaticTest();
- new StaticTest();
- }
- }
- class Father
- {
- public Father()
- {
- 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 包都导入, 而只是想使用某部分函数. 提高代码的阅读性, 更好的理解程序.
- import static java.lang.System.out;
- public class StaticTest
- {
- public static void main(String[] args)
- {
- out.println("import static 测试");
- System.out.println("import static 测试");
- }
- }
输出
import static 测试
import static 测试
会发现, 两者输出是没有区别的, 但是我们少写了 System. 虽然允许这么使用, 但在实际开发中, 我很少发现有同事这么做, 主要是不利于理解, 但好处是如果频繁用这个类, 可以少很多的类名.
===============================================================
如发现错误, 请及时留言, lz 及时修改, 避免误导后来者. 感谢!!!
来源: https://www.cnblogs.com/dslx/p/10639742.html