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);
}
@Override
public 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:1
Mid的静态初始化块
Mid的静态属性b:2
Leaf的静态初始化块
Root的普通初始化块
Root的无参构造
Root的无参构造后a:5
Root的静态方法
Mid的非静态方法
Mid的普通初始化块
Mid的非静态属性c:3
Mid的无参构造
Root的静态方法
Root的非静态方法
Mid的带参构造器疯狂java讲义
Leaf的普通初始化块
Leaf的无参构造
Root的普通初始化块
Root的无参构造
Root的无参构造后a:5
Root的静态方法
Mid的非静态方法
Mid的普通初始化块
Mid的非静态属性c:3
Mid的无参构造
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 expect
class 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);
}
@Override
void 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 = 0
Glyph() 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.java
class Grain {
@Override
public String toString() {
return "Grain";
}
}
class Wheat extends Grain {
@Override
public String toString() {
return "Wheat";
}
}
class Mill {
Grain process() {
return new Grain();
}
}
class WheatMill extends Mill {
@Override
Wheat process() {
return new Wheat();
}
}