从JVM角度谈谈staitc为什么不能调用实例方法
首先要了解一下Java的内存结构:
静态变量存放在方法区中,并且是被所有线程所共享的。Java堆存放的是我们创建的一个个实例变量。
堆区
- 存储的全部是对象,每个对象都包含一个与之对应的class的信息(class的目的是得到操作指令)。
- JVM只有一个堆区被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身。
栈区
- 每个线程包含一个栈区,栈中只保存基本数据类型的对象和自定义对象的的引用,对象本身都存放在堆区中。
- 每个栈中的数据都是私有的,其他栈不能访问。
- 栈分为三个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
方法区
- 又叫静态区,跟堆一样,被所有的线程共享。方法区中包含所有的class和static变量。
- 方法区中包含的都是在整个程序中永远唯一的元素,如class、static变量。
代码分析
自定义一个Person
类:
内存:
我们的方法在调用的时候是从方法区中调用的,但是堆内存不一样,堆内存中的成员变量lastname
是随着对象的产生而产生的,随着对象的消失而消失的。静态变量是所有线程共享的,所以不会消失。
static关键字
特点
- static是一个修饰符,用于修饰成员(成员变量,成员函数),static修饰的成员变量称之为静态变量或类变量。
- static修饰的成员被所有的对象共享。
- static优先于对象存在,因为static的成员随着类的加载就已经存在了。
- static修饰的成员多了一种调用方式,可以直接被类名所调用。
- static修饰的数据是共享数据,对象中存储的是特有的数据。
成员变量和静态变量的区别
- 生命周期不同
成员变量随着对象的创建而存在随着对象的回收而释放。
静态变量随着类的加载而存在随着类的消失而消失。 - 调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用,也可以用类名调用。 - 别名不同
成员变量也称为实例变量。
静态变量称为类变量。 - 数据存储位置不同
成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量存储在方法区的静态区,所以也叫做对象的共享数据。
静态使用的注意事项
- 静态方法只能访问静态成员,非静态既可以访问静态又可以访问非静态。
- 静态方法中不可以使用
this
或者super
关键字。 - static方法是在编译的时候确定的,在类装入内存的时候也同时装入内存了;而非static方法是在类的实例化的时候装入内存的,其必须依赖于类的实例。
问题解答
- static方法执行的时候,其所在的堆栈中是没有指向对象引用的任何信息的,而非static方法在调用的时候又必须要知道调用该方法的引用,所以在static方法中是没有办法调用非static方法的。
- static方法中是不存在this的,而this是一个非常重要的指向对象引用的关键字(每个非static方法中都应该存在,并且指向了调用该方法的对象的引用;非static方法调用该类其他方法的时候实际上是用到了this.method),所以没有this的static方法是不可能直接调用该类中的非static方法的。