关于加载静态结构在加载构造器之前且创建对象遇到的问题?

为什么在静态方法(main方法)中创建本类的对象可以先调用本类中的构造器(这里是系统默认无参构造器),不应该是先等该静态方法(main方法)随着类的加载完后,再在这个类中加载出 这个在该静态方法(main方法)中创建对象的对应构造器,再才可以创建对象?怎么就创建对象调用构造器在加载静态结构之前了呢?
先拿图一图二举例说明一下我自己的理解思路:

img

img

图一:我们知道静态结构是随着类的加载而加载的,所以Student类中的静态属性age和静态方法read()都是随着Student类的加载而加载的;加载完Student类中的静态结构此时再加载构造器,这个时候构造器才加载出来.

图二:再看StudentTest类,此时StudentTest类中的main()方法也是静态方法,故也随着StudentTest类的加载而加载,当加载main()方法中到创建Student类的对象s这一步,此时是调用Student类中已经是在加载好静态结构之后的构造器(系统系统默认的无参构造器),故可创建对象s,并进行在main()方法【注:也是静态方法】中去调用Student类中的静态属性和静态方法。【注:也可调用Student类中的非静态结构,这里我没有具体写出来举例】。

接下来再看图三,也就是我的问题:

img

问:根据上面图一图二的举例的我的思路理解,我们继续看看这张图三代码图:

同样,知道静态结构是随着类的加载而加载的,故这里main()方法也是随着App类的加载而加载,只不过当也加载到创建App类对象a时,它需要调用App类本类中的构造器,问题就出来了:上面图二是在图一已经加载完静态结构后,再调用图一类中的构造器去创建对象;这里图三是在本类App类的main()方法中创建对象,先去调用图三本类App类中的构造器,可是此时main方法是静态方法,应该是随着类的加载而加载的,并且加载完后静态结构才加载构造器,才可以调用构造器,才再可以创建对象,但这里直接在main()方法静态方法中就去调用构造器了,未等静态结构(main()方法)加载完,【与先加载静态结构后加载构造器,才可以调用构造器再创建对象这一道理相矛盾】怎么就跑到加载静态结构之前 加载构造器了,就可以创建对象了,岂不是矛盾?

我也不知道我自己说的够不够清楚,请仔细观看反复查看,错了地方也请指正!所以上面所述就是我困惑的点,虽然在软件idea中可以那样编译运行,都不会报错,但我就是有点矛盾,想不通,望大伙厉害的人 详细仔细耐心慢慢说明,真的感谢!

Java中可以通过类实例调用静态方法,当然不推荐这么做,避免出现意想不到的问题,接下来会讲到,但是在C#中通过类实例调用静态方法在编译时就不会通过,这里做下记录。

类实例调用静态方法
首先我们来看一个简单的例子说明为何不能通过类实例调用静态方法,我们知道未实例化的对象去调用对应方法或者字段时会抛出空指针异常,比如如下:

public static void main(String[] args) {
    Object o = null;
    System.out.println(o.toString());
}

img

但是若将其应用到静态方法上则会出现意想不到的问题,比如如下例子:

public class Player {
    public static final String type = "Human";

    private int age;

    public static String getType() {
        return type;
    }

    public int getAge() {
        return age;
    }
}
public static void main(String[] args) {
    Player player = null;
    System.out.println(player.getType());
    System.out.println(player.getAge());
}

img

上述对象并未实例化,但是调用其变量的静态方法却不会抛出异常并能打印出结果,当然答案也很简单,因为静态方法是属于类而非类实例,所以上述调用 player.getType() 本质上肯定是调用 Player.getType() 。 

总结
在Java中通过类实例可以调用静态方法可能是在最初设计时所产生的缺陷,当然,这只是我个人的揣测,没有再过多深究,看到居然编译不出错而且可以正常运行,认为这一点和C#有很大的区别。

但这里直接在main()方法静态方法中就去调用构造器了,未等静态结构(main()方法)加载完

这个地方我不理解你怎么知道他main()方法没加载完,其实你调用的时候,app这个类中的静态方法已经加载完了

  1. "先加载静态结构后加载构造器"这个没毛病,我们在运行App这个示例时,需要告诉java的入口类是哪一个
    java aaa.App 
    
  2. 第一步jvm会去找aaa/App.class这个文件,它会首先load整个class
  3. 在load的过程中,发现有静态字段/静态代码块,会直接执行,但是方法不会做任何处理
  4. 当执行main方法时,整个App类中的静态字段/静态代码块已经处理完毕,改写下题主的类,运行下就可能更加清晰。
package aaa;

public class App {
    private static Integer integer = new Integer(10);

    static {
        System.out.println("load class invoke:" + integer);
    }

    public App() {
        System.out.println("object construct");
    }

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

    public static void main(String[] args) {
        App a = new App();
        a.show();
    }
}
  1. 执行结果在评论截图

    img

说构造方法也是静态方法,从jvm的角度获取可以这么类比,但是在编程中这种理解不好。
首先构造方法分为静态构造方法和实例构造方法,如果你把实例构造方法当成静态方法,那么静态构造方法怎么类比呢?
另一个问题,构造函数是可以访问成员变量的,而且它往往就是用来初始化成员变量。但是一般静态方法就不可以。所以怎么能类比呢?