public class A {
static {
System.out.println("A static block");
}

public static void method(){
System.out.println("A static method");
}

public static void main(String[] args) {
B.method();
}
}class B extends A{
static {
System.out.println("B static block");
}
}静态代码块在类加载时运行,也就是说JAVA虚拟机知道B的method方法就是A的,但它又没加载B类,怎么知道的呢希望各位大大从 内存,方法区 等 帮忙答疑解惑一下 ~

解决方案 »

  1.   

    忘了说了 ,上面代码输出:
    A static block
    A static method
      

  2.   

    http://www.sunxin.org/forum/thread/23317.html
    这有一个关于静态代码块执行的介绍.
      

  3.   

    你要理解,静态代码只执行一次,
    而且在类初化的时候就执行。
    所以打印出来了你看的,至于你的B.method() 因为他是继续的B的方法,所以他不再执行了
      

  4.   

    我的问题是为什么 没有 “B static block”为什么不加载B类 就知道它的method是继承自A的
      

  5.   

    弱弱的说 下 你的B类里面有method() 这个方法? 
      

  6.   

    是我的表达能力太差呢,还是各位没仔细看呢
    我的问题和静态代码块没什么关系,只是用它来验证类有没有被加载。我想问的是为什么B类没被加载,就能执行其继承自A的static方法,虽然这个方法是A的。
    但B类没被加载的话,JVM 怎么知道它的method方法就是A的,直接执行了A的method的呢。
      

  7.   

    B extends A 所以B包含A中的方法 自然包括method方法 而method是static 方法 所以在运行
    B.method()的时候B并没有实例化 B类里面的static块也不会运行 但是由于method方法是静态的所以B.method()实际上就是调用static{
      System.out.println("A static method");
    }
      

  8.   

    只有当你这样写的时候:B b=new B();
    B类的静态代码块里的句子才有机会打印出来,或者,在A类里有用到了B类自己本身独有的或重写的方法等,
    否则,
    B类只可能被隐式加载,而不可能打印出B静态代码块的句子..B类一定是已经加载进去了,否则A类的main方法早就编译就报错了,何必等到执行..之所以没看到显式的东西,是因为你没用到,JVM虚拟机又有强大的垃圾回收功能,那些没用到的变量和废弃的引用,你根本就察觉不到.
      

  9.   

    static块不是在实例化时运行,是在类加载的时候
      

  10.   


    只有当你这样写的时候:B b=new B();
    B类的静态代码块里的句子才有机会打印出来那为什么A类的静态代码块里的句子反而被打印出来了呢
    还是一样  static块不是在实例化时运行,是在类加载的时候
      

  11.   

    B根本没有被加载 运行A中的静态方法所以A类一开始就被加载了 
      

  12.   


    问题就在与此-_-||,为什么B没加载,JVM就知道B.method其实就是去调用A的method呢?
      

  13.   


    B.method可以调用,而B没有被加载我觉得是因为JVM在调用B.method时只获得B的元数据而没有进行B的加载而元数据都存放到(Permanent Space),只有B加载时B的static块才会运行,这样B会在(The Heap Space)中被创建,从而由JVM来维护其生命周期。http://blog.csdn.net/soulx/archive/2010/03/01/5335203.aspx
    LZ可以看下这个,或许会有所帮助。
      

  14.   

    开始时,本人也有同样的疑问。
    静态代码段是在类装载的时候运行、初始化一次,既然那段B static没有运行 说明B根本就没加载。再考虑一下很可能是jvm的优化吧。
    把你原来代码改一下public class A
    {

    static
    {
    System.out.println("A static block");
    }
      public static void method()
    {
    System.out.println("A static method");
    } public static void main(String[] args)
    {
    //B.method();
    B.B_method();
    }
    }class B extends A
    {
    static
    {
    System.out.println("B static block");
    }
    static void B_method()
    {
    System.out.println("B self static block");
    }
    }也就是添加了B自己的static方法
    输出结果如下:
    A。
    B static......
    B self static....说明jvm装载了类B
    如果单纯根据这一点的话,可以得出结论:由于jvm知道B的method()是继承自A的,这点在JVM实例的方法栈中的类型信息可以查询到的,所以就干脆做了优化,不装载类B,因为装载一个类要涉及装载、GC的消耗效率的问题。
    继续修改public class A
    {

    static
    {
    System.out.println("A static block");
    }
      public static void method()
    {
    System.out.println("A static method");
    } public static void main(String[] args)
    {
    //B.method();
    B.method();
    }
    }class B extends A
    {
    static
    {
    System.out.println("B static block");
    }
    public static void method()
    {
    System.out.println("B self static block");
    }
    }也就是覆盖了A中的同名方法
    运行之,结果是
    A....
    B static ....
    B self static...
    加载了类,因为B覆盖了父类A的同名方法,所以运行时,jvm 不知道B到底哪个method(),加载之。ps:当然不排除有些文章讲的 不同编译器(不是JVM)带来的优化,事实上,java编译器做优化的不多吧,可能是受到了class文件那严格的格式要求限制,只是猜测而已。
      

  15.   

    你写个类,在 main 方法中只写上这一句话 Class.forName(A.class.getName()); 那就表示加载类了。其中的 静态块就会执行。
      

  16.   


    类的加载顺序
    什么时候类加载
    第一次需要使用类信息时加载。
    类加载的原则:延迟加载,能不加载就不加载。触发类加载的几种情况:
    (1)、调用静态成员时,会加载静态成员真正所在的类及其父类。
    通过子类调用父类的静态成员时,只会加载父类而不会加载子类。
    (2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。
    (3)、加载子类会先加载父类。(覆盖父类方法时所抛出的异常不能超过父类定义的范围)
    注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。
    例:public static final int a =123;
    但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。
    例:public static final int a = math.PI
    如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载;
    如果编译时不能确定其值的话,则运行时加载
    类加载的顺序:
    1.加载静态成员/代码块:
    先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。
    同一个类里的静态成员/代码块,按写代码的顺序加载。
    如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。
    调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。
    2.加载非静态成员/代码块:(实例块在创建对象时才会被加载。而静态成员在不创建对象时可以加载)
    先递归地加载父类的非静态成员/代码块(Object的最先);再依次加载到本类的非静态成员。
    同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。
    但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null 或者 0)。
    调用父类的非静态成员(private 除外),也可以像调用自己的一样。
    3.调用构造方法:
    先递归地调用父类的构造方法(Object的最先);默认调用父类空参的,也可在第一行写明调用父类某个带参的。
    再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。
    注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。
    其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。
    假设子类override父类的所有成员,包括静态成员、非静态属性和非静态方法。
    由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;
    由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。 引用至:http://hi.baidu.com/yuxueren/blog/item/415b8401d2260a0c1d958398.html
      

  17.   


    那看来就是这样了
    不过我有个问题 JVM在什么时候获得B是A类 子类 这个信息的?
      

  18.   

    如果声明为static时,就是在调用这个类的时候就执行了,并且在内存中只有一份。
      

  19.   

    可以看一下《Inside JVM》中active use的意义。
      

  20.   

    我想这是一个关于java的静态绑定的问题,当方法时private、static、final方法或者构造器,那么编译器将可以准确的知道应该调用哪个方法。所以,当你的程序运行的时候,虚拟机已经知道B.method是调用A的静态方法,所以,B类没有被加载。
    个人愚见,希望高手补充!
      

  21.   

    补充一点,java的静态绑定时在编译时绑定的,所以真正的代码内部已经用A.method将B.method代替了。我是这样想的,希望对楼主有帮助。
      

  22.   


    看了下 .class文件 编译器好像没这么干
      

  23.   

    类的加载顺序
      父类的static块, 子类的static块 块就是'{ }'
      父类的非static块, 子类的非static块
      父类的构造器, 子类的构造器
      

  24.   

    我也有疑问,我的理解是:
      这个先要看看静态初始化块执行的顺序,然后就是jvm优化的问题和垃圾回收问题。
    先看看静态初始化块执行顺序:
      A(父)—继承—B—继承—C(子)
    在运行子类时候会先执行其顶层父类的静态初始化块,再执行其直系父类的初始化块,最后再执行本身的初始化块。
      现在来看看这个问题(以你的例子为例子),用B调用A中方法的时候要先运行A的初始化块,接着如果B没有调用A中方法的话会执行B的初始化块;但是现在你调用了A中的方法而且是用子类调用。后面的问题我觉得是jvm优化和垃圾回收,具体我也说不知道。
    等待强人吧!
      

  25.   

    楼主有没有试过把main方法放到B类的情况???
      

  26.   

    这个问题要看jvm指令invokestatic的行为了,我用javap看了一下指令码,其中的main如下:const #5 = Method       #25.#26;        //  B.method:()Vpublic static void main(java.lang.String[]);
      Code:
       Stack=0, Locals=1, Args_size=1
       0:   invokestatic    #5; //Method B.method:()V
       3:   return
      LineNumberTable:
       line 11: 0
       line 12: 3根据sun官方网站的说明,invokestatic首先会去“定位”静态方法method所属的类(先从#5指定的类B开始进行回溯搜索),找到这个类以后(在这里就是类A了),如果这个类没有初始化,才开始初始化这个类。而类B并不会在jvm的回溯搜索过程中进行类初始化的。参考文献:http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc6.html
      

  27.   

    Java中的初始化类、变量、程序块加载探讨 http://www.phome.asia/forum/thread/17615.html