zoukankan      html  css  js  c++  java
  • 类的加载机制

    最近有很多同学开始学习Java,都问了我一个很基础的问题:

    public class MethodInvokeTest{
    	int i = 0;
    
    	public static void main(String[] args) {
    		System.out.println(i);
    	}
    }
    

    这种情况下为什么不可以输出i。由于自己也才入门Java不久,只是大概记得是因为Java类加载机制的问题,所以在认真查找了一下资料,并转载一下别人的博客,来加深印象,并供将来自己复习。

    Java程序运行时,第一件事情就是试图访问main方法,因为main相等于程序的入口,如果没有main方法,程序将无法启动,main方法更是占一个独立的线程,找到main方法后,是不是就会执行mn方法块里的第一句话呢?答案是不一定

    例如以下情况:

    public class Test1 {
    public static String name;
        public Test1() {
        }
        public static void get() {
            System.out.println("Test start");
        }
        public static void main(String[] args) {
            System.out.println("main start");
            Test1 bb = new Test1();
        }
    }
    

    因为静态部分是依赖于类,而不是依赖于对象存在的,所以静态部分的加载优先于对象存在。

      当找到main方法后,因为main方法虽然是一个特殊的静态方法,但是还是静态方法,此时JVM会加载main方法所在的类,试图找到类中其他静态部分,即首先会找main方法所在的类。

    执行顺序大致分类:

      1.静态属性,静态方法声明,静态块。

      2.动态属性,普通方法声明,构造块。

      3.构造方法。(从构造方法传参,你在debug模式下就会发现,是在最后赋值)

    1.1 静态:

      当加载一个类时,JVM会根据属性的数据类型第一时间赋默认值(一举生成的)。然后再进行静态属性初始化,并为静态属性分配内存空间,静态方法的声明,静态块的加载,没有优先级之分,按出现顺序执行,静态部分仅仅加载一次。至此为止,必要的类都已经加载完毕,对象就可以被创建了。

    1.2 普通:

      当new一个对象时,此时会调用构造方法,但是在调用构造方法之前,(此刻1.1已经完成,除非被打断而暂停)执行动态属性定义并设置默认值(一举生成的)。然后动态属性初始化,分配内存,构造块,普通方法声明(只是加载,它不需要初始化,只有调用它时才分配内存,当方法执行完毕后内存立即释放),没有优先级之分,按出现顺序执行。最后进行构造方法中赋值。当再次创建一个对象,不再执行静态部分,仅仅重复执行普通部分。

      注意:如果存在继承关系,创建对象时,依然会首先进行动态属性进行定义并设默认值,然后父类的构造器才会被调用,其他一切都是先父类再子类(因为子类的static初始化可能会依赖于父类成员能否被正确初始化),如果父类还有父类,依次类推,不管你是否打算产生一个该父类的对象,这都是自然发生的。

    下面可以做一道测试题:

    class A {
        public A() {
            System.out.println("A的构造方法");
        }
    
        public static int j = print();
    
        public static int print() {
            System.out.println("A print");
            return 521;
        }
    }
    
    public class Test1 extends A {
        public Test1() {
            System.out.println("Test1的构造方法");
        }
    
        public static int k = print();
    
        public static int print() {
            System.out.println("Test print");
            return 522;
        }
    
        public static void main(String[] args) {
            System.out.println("main start");
            Test1 t1 = new Test1();
        }
    }
    

    结果:
    A print
    Test print
    main start
    A的构造方法
    Test1的构造方法

    转载自:https://www.cnblogs.com/greatfish/p/5771548.html

  • 相关阅读:
    Jenkins
    ssh 免登录
    linux 远程执行命令
    Java WEB 笔记
    如何用新安装的jdk替换掉Linux系统默认jdk
    修改 File --> New 菜单内容
    java.security.NoSuchAlgorithmException: AES KeyGenerator not available
    JDK历史版本下载地址
    maven 核心概念
    spring boot: ConfigurationProperties
  • 原文地址:https://www.cnblogs.com/DevLegal/p/9116810.html
Copyright © 2011-2022 走看看