The Wayback Machine - https://web.archive.org/web/20210207134551/https://github.com/Snailclimb/JavaGuide/issues/972
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于静态方法为什么不能调用非静态代码的原因? #972

Open
kebukeyi opened this issue Oct 29, 2020 · 5 comments
Open

关于静态方法为什么不能调用非静态代码的原因? #972

kebukeyi opened this issue Oct 29, 2020 · 5 comments
Labels

Comments

@kebukeyi
Copy link

@kebukeyi kebukeyi commented Oct 29, 2020

   静态方法是属于类的而动态方法属于实例对象,因此在类加载的时候就会为其分配内存,可以通过类名直接去访问,非静态成员(变量和方法)属于类的对象,所以只有该对象初始化之后才存在,然后通过类的对象去访问。所以说如果我们在静态方法中调用非静态成员变量会超前,可能会调用了一个还未初始化的变量,因此编译器会报错。
@ZacBi
Copy link

@ZacBi ZacBi commented Oct 30, 2020

@kebukeyi 你cite的这段就是原因

@Snailclimb
Copy link
Owner

@Snailclimb Snailclimb commented Oct 31, 2020

   静态方法是属于类的而动态方法属于实例对象,因此在类加载的时候就会为其分配内存,可以通过类名直接去访问,非静态成员(变量和方法)属于类的对象,所以只有该对象初始化之后才存在,然后通过类的对象去访问。所以说如果我们在静态方法中调用非静态成员变量会超前,可能会调用了一个还未初始化的变量,因此编译器会报错。

👍可以指出具体需要完善的位置。
可以提交一个PR完善一下不?

@ZacBi
Copy link

@ZacBi ZacBi commented Oct 31, 2020

@kebukeyi 更详细的来说你得看类加载对象创建了, ref: 深入理解JVM

@zouyishan
Copy link

@zouyishan zouyishan commented Dec 27, 2020

说一下我的看法:我们可以直接用类名调用静态方法,这个静态方法肯定必须要在我们调用之前就要被初始化好,那么也就是说在类被加载的时候就会被初始化好了。具体阶段应该在类加载的初始化阶段,这时会执行clint方法对静态变量进行赋值和static{}代码块的初始化。这时候是不知道有非静态代码的。所以会报错
创建实例对象的时候就可以发现对于static{}中的代码先执行,然后再是{}代码块里面的被执行,再是构造方法被执行。而当构造方法被执行时,一个对象实例再算创建。这时候才能调用非静态的代码,所以静态方法是不能调用非静态代码的

@ZacBi
Copy link

@ZacBi ZacBi commented Dec 29, 2020

  @zouyishan 讲的差不多是这个意思, 但是有点偏差, 我补充一下.

  首先, JVM中方法是不存在initialization这个过程的, 确切的描述应该是调用执行. 此外, 类加载的时候, 才存在类初始化这个阶段.

  zouyishan的解释可以理解为这么一句话:

You can't call something that doesn't exist. Since you haven't created an object, the non-static method doesn't exist yet. A static method (by definition) always exists.

  更深一点的探究应该涉及到方法调用的过程. 如果运行时能够发生静态方法A调用实例方法B, 其过程应该如下:

  1. 当前线程在虚拟机栈中建立A的栈帧
  2. A调用B, 虚拟机栈中建立B的栈帧
  3. B作为实例方法, 其栈帧的局部变量表中索引为0处应该存放对应实例对象在内存布局中的地址. 但实例还未被创建, 所以报错.

  但是Java编译器会在编译时就检查到这类错误, 直接报错.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants