tips:
-
静态:static
用法:是一个修饰符;用于修饰成员(成员变量和成员函数)
当成员被静态修饰后,就多了一种调用方式,除了可以被对象调用外,还可以直接被类名调用格式:类名.静态成员 -
静态的特点:
- 随着类的加载而加载,也就是,说静态会随着类的消失而消失,说明静态的生命周期最长
- 优先于对象的存在,明确一点:静态是先存在的对象是后存在的
- 被所有对象共享
- 可以直接被类名多调用
-
实例变量和类变量的区别
- 存放位置:类变量随着类的加载存在于方法区中,实例变量随着对象的对象的建立存在于堆内存里
- 生命周期:类变量生命周期最长,随着“类”的加载而加载,随着类的消失而消失;实例变量随着“对象”的消失而消失
-
静态的使用注意事项:
- 静态方法只能访问静态成员(包括成员变量和成员方法);非静态方法可以访问静态也可以访问非静态
- 静态方法中不可以定义this,super关键字;因为静态优先于对象存在,所以静态方法中不可以出现this,super关键字
- 主函数是静态的。
-
静态的利弊
- 利:对 对象的共享数据进行单独空间的存储,节省空间,没有必要没一个对象中都存储一份
可以直接被类名所调用 - 弊:生命周期过长,访问出现局限性(只能访问静态)
- 利:对 对象的共享数据进行单独空间的存储,节省空间,没有必要没一个对象中都存储一份
所以得出:
因为静态是随着类的加载而加载的 也就是说类只要存在了,那么静态就存在了,而静态是优先于对象存在的 ,你要访问非静态的东西,也就是非静态的成员(包括变量和方法),非静态的东西还没存在你怎么访问的到吗??
对上面结论做出解释案例:
究其原因,我们来做如下分析:
任何程序最终都是在内存中执行的,变量只有在内存中占有一席之地时才能被访问,不在内存中的变量就不能被访问。类的静态成员(变量和方法)都属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。
public class StaticDemo {
static int x;
static void fun() {
System.out.println("this is fun()");
}
public static void main(String[] args) {
StaticDemo.x = 5; // 可以用类名直接访问静态成员
fun(); // 在类体内也可以直接访问
}
}
由于静态成员在类加载的时候就会被分配内存,而非静态成员则不会。因此,在一个类的静态成员中去访问其非静态成员会出错,是因为在类的非静态成员不存在的时候,类的静态成员就已经存在了,访问一个内存中不存在的东西当然会出错。
而类又是在什么时候加载的呢?核心类(比如String类)在 JVM 启动时(main 方法开始执行前)就会被加载,其它类在使用前(实例化对象、调用其静态方法、访问静态域等前)会被动态加载。
需注意:子类被加载前,它的所有超类要根据由父到子的顺序被逐一加载。
如下例子:
class A1 {
public static int a = 5;
}
class B1 extends A1 {
public static int a = 8;
void print() {
System.out.println(super.a);
System.out.println(a);
}
}
// 测试类
public class TestStatic {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("b.a="+B1.a);
System.out.println("b.a="+A1.a);
new B1().print();
}
}
最终的运行结果如下:
b.a=8
b.a=5
5
8
代码解析:
当你在dos环境下输入:java TestStatic时
-
(1)JVM会首先加载TestStatic类,此时JVM会先看看TestStatic类是否存在static字段,没有,直接执行main方法;如果有静态变量则先加载静态变量
-
(2)main方法第一句是打印B1.a, JVM便会去找类B1,找到B1时,发现B1的父类是A1,于是父亲A1被优先加载;
-
(3)在加载A1时,会扫描A1中是否存在static的成员(静态变量、静态方法),发现存在静态变量a(static int a = 5) ,先加载,当把所有static的字段加载完,一个类就加载完成了,以后就无需再加载了; 这里就已经对A1类进行了加载,后面就不会加载它了,用到了也只会到方法区加载字节码信息
-
(4)父亲加载完成了,才轮到子类B1的加载,同样先扫描B1中是否存在static的字段,发现存在静态变量a(static int a = 8),加载a,此时B1也加载完毕了;
第一条print语句到此时也执行完毕了。
轮到下一条print语句了(new B1().print()),当执行这句时,会发生动态绑定,此时会有一个代表B1对象的this对象传递给print()方法,所以print()方法中的 System.out.println(a); 其实是System.out.println(this.a),会打印出一个8。至于super.a就是打印父类中的a,结果是5。
到此,main()方法执行完,整个程序退出。
扩展
这里可以研究一下类的加载顺序?什么情况下会触发类的加载机制?jvm的加载机制又是怎样的?等问题
参考:
为什么静态方法不能调用非静态的变量和方法
为什么不能从静态的方法里面调用非静态方法,或变量?
(转载)为什么不能从static方法调用非static的方法或变量?