java 类何时会被加载
java类在以上五种情况下会被加载。
在jvm生命周期中每个类如果存在,则不会重复加载。
在加载子类的时候会优先加载其父类。
类被加载的时候,其中的静态代码块、静态方法及静态变量也会被加载。
在初始化某个类时,如果这个类的静态代码块、静态方法或静态变量引用到了另一个类,则这个类也会被加载。
————————————————
版权声明:本文为CSDN博主「瀚忄」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_30233335/article/details/114390832
类的加载顺序
有父子关系的类在加载时
先调用父类静态初始化块->静态属性(不包括静态方法)
然后是子类
子类静态初始化块->静态属性(不包括静态方法)
创建对象的过程
先是父类非静态初始化块,非静态属性 ,再是父类构造函数
然后是子类非静态初始化块,非静态属性 ,最后是子类构造函数
注意
(1)子类在继承父类后,若重写了父类的方法,那么父类中这个方法会被隐藏,但是可以通过在构造方法中用super显示调用。
(2)父类的静态方法是不能被继承的
(3)如果父类没有写出默认的无参构造方法但有写出有参的构造方法,那么在子类的构造方法中不需显示调用,不然会报错。
(4)静态代码块和静态变量只会在class加载时初始化,之后new新对象时如果没有显示的调用,不会再执行
package com.zqt.basicproject;public class InitSort {public static void main(String[] args) {new Leaf();new Leaf();}}class Root {static int a = 1;static {System.out.println("Root的静态初始化块");System.out.println("Root的静态属性a:" + a);}{System.out.println("Root的普通初始化块");}public static void init() {System.out.println("Root的静态方法");}public void normal() {System.out.println("Root的非静态方法");}public Root() {a = 5;System.out.println("Root的无参构造");System.out.println("Root的无参构造后a:"+a);init();normal();//this.normal();结果:Mid的非静态方法}}class Mid extends Root {static int b = 2;int c = 3;static {System.out.println("Mid的静态初始化块");System.out.println("Mid的静态属性b:" + b);}{System.out.println("Mid的普通初始化块");System.out.println("Mid的非静态属性c:"+ c);}@Overridepublic void normal() {//super.normal();System.out.println("Mid的非静态方法");}public Mid() {System.out.println("Mid的无参构造");}public Mid(String name) {this();super.init();super.normal();System.out.println("Mid的带参构造器" + name);}}class Leaf extends Mid {static {System.out.println("Leaf的静态初始化块");}{System.out.println("Leaf的普通初始化块");}public Leaf() {super("疯狂java讲义");System.out.println("Leaf的无参构造");}}
结果
Root的静态初始化块Root的静态属性a:1Mid的静态初始化块Mid的静态属性b:2Leaf的静态初始化块Root的普通初始化块Root的无参构造Root的无参构造后a:5Root的静态方法Mid的非静态方法Mid的普通初始化块Mid的非静态属性c:3Mid的无参构造Root的静态方法Root的非静态方法Mid的带参构造器疯狂java讲义Leaf的普通初始化块Leaf的无参构造Root的普通初始化块Root的无参构造Root的无参构造后a:5Root的静态方法Mid的非静态方法Mid的普通初始化块Mid的非静态属性c:3Mid的无参构造Root的静态方法Root的非静态方法Mid的带参构造器疯狂java讲义Leaf的普通初始化块Leaf的无参构造
————————————————
版权声明:本文为CSDN博主「Damon_zqt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Damon_zqt/article/details/105384791
java多态
1.当重写了父类的方法时。如果调用父类的方法,编译器会自动调用对应对象(子类对象)的方法实现。
// polymorphism/PolyConstructors.java// Constructors and polymorphism// don't produce what you might expectclass Glyph {void draw() {System.out.println("Glyph.draw()");}Glyph() {System.out.println("Glyph() before draw()");draw();System.out.println("Glyph() after draw()");}}class RoundGlyph extends Glyph {private int radius = 1;RoundGlyph(int r) {radius = r;System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);}@Overridevoid draw() {System.out.println("RoundGlyph.draw(), radius = " + radius);}}public class PolyConstructors {public static void main(String[] args) {new RoundGlyph(5);}}
输出:[
](https://blog.csdn.net/weixin_30233335/article/details/114390832)
Glyph() before draw()RoundGlyph.draw(), radius = 0Glyph() after draw()RoundGlyph.RoundGlyph(), radius = 5
Glyph 的 draw() 被设计为可重写,在 RoundGlyph 这个方法被重写。但是 Glyph 的构造器里调用了这个方法,结果调用了 RoundGlyph 的 draw() 方法,这看起来正是我们的目的。输出结果表明,当 Glyph 构造器调用了 draw() 时,radius 的值不是默认初始值 1 而是 0。这可能会导致在屏幕上只画了一个点或干脆什么都不画,于是我们只能干瞪眼,试图找到程序不工作的原因。
前一小节描述的初始化顺序并不十分完整,而这正是解决谜团的关键所在。初始化的实际过程是:
- 在所有事发生前,分配给对象的存储空间会被初始化为二进制 0。
- 如前所述调用基类构造器。此时调用重写后的 draw() 方法(是的,在调用 RoundGraph 构造器之前调用),由步骤 1 可知,radius 的值为 0。
- 按声明顺序初始化成员。
- 最终调用派生类的构造器。
这么做有个优点:所有事物至少初始化为 0(或某些特殊数据类型与 0 等价的值),而不是仅仅留作垃圾。这包括了通过组合嵌入类中的对象引用,被赋予 null。如果忘记初始化该引用,就会在运行时出现异常。观察输出结果,就会发现所有事物都是 0。
另一方面,应该震惊于输出结果。逻辑方面我们已经做得非常完美,然而行为仍不可思议的错了,编译器也没有报错(C++ 在这种情况下会产生更加合理的行为)。像这样的 bug 很容易被忽略,需要花很长时间才能发现。
因此,编写构造器有一条良好规范:做尽量少的事让对象进入良好状态。如果有可能的话,尽量不要调用类中的任何方法。在构造器中唯一能安全调用的只有基类的 final 方法(包括 private 方法,它们自动属于 final)。这些方法不能被重写,因此不会产生意想不到的结果。你可能无法永远遵循这条规范,但应该朝着它努力。
2.子类中重写父类的方法时,可以返回父类方法返回类型的子类型
// polymorphism/CovariantReturn.javaclass Grain {@Overridepublic String toString() {return "Grain";}}class Wheat extends Grain {@Overridepublic String toString() {return "Wheat";}}class Mill {Grain process() {return new Grain();}}class WheatMill extends Mill {@OverrideWheat process() {return new Wheat();}}
