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类,怎么知道的呢希望各位大大从 内存,方法区 等 帮忙答疑解惑一下 ~
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类,怎么知道的呢希望各位大大从 内存,方法区 等 帮忙答疑解惑一下 ~
解决方案 »
- java MP3播放 界面
- 两个线程可以同时访问被synchronized修饰的包含同一共享数据的方法吗?
- JAVA中十进制的UNICODE如何转换成中文或者中文转换成十进制的UNICODE
- 书上的例子,有不明白的地方,麻烦解释下
- 一个JTable 放在JScrollPane中,如果这个JTable有50行,而JScrollPane中一页只能显示20行,我想让JTable 从第25行开始显示,怎么做?
- Unix下面的URLEncoder.encode()不正常!怎么回事?高手来看看!多谢了!--在线等待!!!
- 新手上路,问servlet过滤器问题,跪求高手解答,谢谢
- 能否进一步解释一下inputStream类的mark()方法中的参数readlimit的具体含义
- -1>>32还是-1, -1>>>32为什么还是-1?
- 是用getBundle();的问题
- java替换字符串
- Integer包装类问题
A static block
A static method
这有一个关于静态代码块执行的介绍.
而且在类初化的时候就执行。
所以打印出来了你看的,至于你的B.method() 因为他是继续的B的方法,所以他不再执行了
我的问题和静态代码块没什么关系,只是用它来验证类有没有被加载。我想问的是为什么B类没被加载,就能执行其继承自A的static方法,虽然这个方法是A的。
但B类没被加载的话,JVM 怎么知道它的method方法就是A的,直接执行了A的method的呢。
B.method()的时候B并没有实例化 B类里面的static块也不会运行 但是由于method方法是静态的所以B.method()实际上就是调用static{
System.out.println("A static method");
}
B类的静态代码块里的句子才有机会打印出来,或者,在A类里有用到了B类自己本身独有的或重写的方法等,
否则,
B类只可能被隐式加载,而不可能打印出B静态代码块的句子..B类一定是已经加载进去了,否则A类的main方法早就编译就报错了,何必等到执行..之所以没看到显式的东西,是因为你没用到,JVM虚拟机又有强大的垃圾回收功能,那些没用到的变量和废弃的引用,你根本就察觉不到.
只有当你这样写的时候:B b=new B();
B类的静态代码块里的句子才有机会打印出来那为什么A类的静态代码块里的句子反而被打印出来了呢
还是一样 static块不是在实例化时运行,是在类加载的时候
问题就在与此-_-||,为什么B没加载,JVM就知道B.method其实就是去调用A的method呢?
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可以看下这个,或许会有所帮助。
静态代码段是在类装载的时候运行、初始化一次,既然那段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文件那严格的格式要求限制,只是猜测而已。
类的加载顺序
什么时候类加载
第一次需要使用类信息时加载。
类加载的原则:延迟加载,能不加载就不加载。触发类加载的几种情况:
(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
那看来就是这样了
不过我有个问题 JVM在什么时候获得B是A类 子类 这个信息的?
个人愚见,希望高手补充!
看了下 .class文件 编译器好像没这么干
父类的static块, 子类的static块 块就是'{ }'
父类的非static块, 子类的非static块
父类的构造器, 子类的构造器
这个先要看看静态初始化块执行的顺序,然后就是jvm优化的问题和垃圾回收问题。
先看看静态初始化块执行顺序:
A(父)—继承—B—继承—C(子)
在运行子类时候会先执行其顶层父类的静态初始化块,再执行其直系父类的初始化块,最后再执行本身的初始化块。
现在来看看这个问题(以你的例子为例子),用B调用A中方法的时候要先运行A的初始化块,接着如果B没有调用A中方法的话会执行B的初始化块;但是现在你调用了A中的方法而且是用子类调用。后面的问题我觉得是jvm优化和垃圾回收,具体我也说不知道。
等待强人吧!
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