搞清java中的类加载问题 |
您所在的位置:网站首页 › static静态代码块 › 搞清java中的类加载问题 |
{ System.out .println("h"); } privateinti =test; static{ System.out .println("f"); } privatestaticintj =method; Dog{ System.out .println("g"); } publicinttest{ System.out .println("i"); return1; } publicstaticintmethod{ System.out .println("j"); return1; } publicstaticvoidmain(String[]args ){ Dogdog =newDog; System.out .println; Dogdog1 =newDog; } } 执行这段main程序,会输出什么? 答案是 eafjicbhig icbhig 为了方便大家一个个细节去理解, 我换一种方式去提问。 Q: 什么时候会进行静态变量的赋值和静态代码块的执行? A: 第一次创建某个类或者某个类的子类的实例 访问类的静态变量、调用类的静态方法 使用反射方法forName 调用主类的main方法(本例子的第一次静态初始化其实属于这个情况,调用了Dog的main方法) 注: 类初始化只会进行一次, 上面任何一种情况触发后,之后都不会再引起类初始化操作。Q:初始化某个子类时,也会对父类做静态初始化吗?顺序呢? A:如果父类之前没有被静态初始化过,那就会进行, 且顺序是先父类再子类。 后面的非静态成员初始化也是如此。 所以会先输出eafj。 Q: 为什么父类的method不会被子类的method重写? A: 静态方法是类方法,不会被子类重写。毕竟类方法调用时,是必定带上类名的。 Q: 为什么第一个输出的是e而不是a? A: 因为类变量的显示赋值代码和静态代码块代码按照从上到下的顺序执行。 Animal的静态初始化过程中,method的调用在static代码块之前,所以先输出e再输出a。 而Dog的静态初始化过程中,method的调用在static代码块之后,因此先输出f,再输出j Q: 没有在子类的构造器中调用super时,也会进行父类对象的实例化吗? A: 会的。会自动调用父类的默认构造器。 super主要是用于需要调用父类的特殊构造器的情况。 因此会先进行Animal的对象实例化,再进行Dog的对象实例化 Q: 构造方法、成员显示赋值、非静态代码块(即输出c和h的那2句)的顺序是什么? A: Q: 为什么Animal实例化时, i=test中输出的是i而不是d? A:因为你真正创建的是Dog子类,Dog子类中的test方法由于签名和父类test方法一致,因此test方法被重写了。 此时即使在父类中调用,也还是用使用子类Dog的方法。除非你new的是Animal。 Q: 同上题, 如果test方法都是private或者final属性, 那么上题的情况会有变化吗?? A: 因为private和final方法是不能被子类重写的。 所以Animal实例化时,i=test输出d。 总结一下顺序: Q:类加载的3个必经阶段是: A: Q:new某个类的数组时,会引发类初始化吗? 像下面输出什么 publicclassTest{ staticclassA{ publicstaticinta =1; static{ System.out .println("initA"); } } publicstaticvoidmain(String[]args ){ A[]as =newA[5]; } } A: new数组时,不会引发类初始化。 什么都不输出。 Q:引用类的final静态字段,会引发类初始化吗? 像下面输出什么? publicclassTest{ staticclassA{ publicstaticfinalinta =1; static{ System.out .println("initA"); } } publicstaticvoidmain(String[]args ){ System.out .println("A.a="+A.a ); } } A: 不会引发。 不会输出initA。 去掉final就会引发了。 (注意这里必须是基本类型常量, 如果是引用类型产量,则会引发类初始化) Q: 子类引用了父类的静态成员,此时子类会做类初始化嘛? 如下会输出什么 publicclassTest{ staticclassA{ publicstaticinta =1; static{ System.out .println("initA"); } } staticclassBextendsA{ static{ System.out .println("initB"); } } publicstaticvoidmain(String[]args ){ System.out .println("B.a="+B.a ); } } A: 子类不会初始化。 打印initA,却不会打印initB。 类加载器 双亲委派 类加载时的双亲委派模型,不知道能怎么出题。。。反正就记得优先去父类加载器中看类是否能加载。 就贴个图吧 注意,上面的图有问题。 Bootsrap不是ClassLoader的子类,他是C++编写的。 而ExtClassLoader和AppClassLoader都是继承自ClassLoader的 Q: java中, 是否类和接口的包名和名字相同, 那么就一定是同一个类或者接口? A: 错误。 1个jvm中, 类和接口的唯一性由 二进制名称以及它的定义类加载器共同决定。 因此2个不同的加载器加载出来相同的类或接口时, 实际上是不同的。 breakDawn返回搜狐,查看更多 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |