• Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序


    直接上代码:

    代码1:

    public class ConstroctTest {
        private static ConstroctTest test = new ConstroctTest();
        //静态变量sta1    未赋予初始值
        public static int sta1;
        //静态变量sta1    赋予初始值20
        public static int sta2 = 20;
        //构造方法中对于静态变量赋值
        private ConstroctTest() {
            sta1 ++ ;
            sta2 ++ ;
        }
        public static void main(String[] args) {
            System.out.println(ConstroctTest.sta1);
            System.out.println(ConstroctTest.sta2);
        }
    }

    结果:

    1
    20

    代码2:

    public class ConstroctTest {
        //静态变量sta1    未赋予初始值
        public static int sta1;
        //静态变量sta1    赋予初始值20
        public static int sta2 = 20;
        private static ConstroctTest test = new ConstroctTest();
        //构造方法中对于静态变量赋值
        private ConstroctTest() {
            sta1 ++ ;
            sta2 ++ ;
        }
        public static void main(String[] args) {
            System.out.println(ConstroctTest.sta1);
            System.out.println(ConstroctTest.sta2);
        }
    }

    结果:

    1
    21

    结果分析:

    1. 按照静态变量的顺序,初始化各静态变量。(给变量赋予默认值)

    2. 按照顺序,赋予静态变量的初始值。

    3. 以上结果在于:类静态变量的位置,决定着通过构造方法给sta1 与 sta2 赋予的值是否有效。

    4. 在代码一中,先对于sta2 执行了 sta2 ++ 操作。而后给sta2 赋予静态变量值。(只因为顺序问题)

    代码3:

    public class ConstroctTest {
        //静态变量sta1    未赋予初始值
        public static int sta1;
        //静态变量sta1    赋予初始值20
        public static int sta2 = 20;
        private static ConstroctTest test = new ConstroctTest();
        //构造方法中对于静态变量赋值
        private ConstroctTest() {
            System.out.println("123456");
            sta1 ++ ;
            sta2 ++ ;
        }
        public static void main(String[] args) {
            System.out.println(ConstroctTest.sta1);
            System.out.println(ConstroctTest.sta2);
            System.out.println(ConstroctTest.sta1);
            System.out.println(ConstroctTest.sta1);
        }
    }

    结果:

    结果分析:

    1. 从结果可以看出,Java的静态变量,只是在类第一次加载,初始化的时候执行。

    2. 类变量不依赖类的实例,类变量只在初始化时候在栈内存中被分配一次空间,无论类的实例被创建几次,都不再为类变量分配空间。

    3. 可以看出 ,类变量的执行与初始化,与实例对象没有关系。

    代码4:

    public class Test{
        public static void main(String[] args){
            Child ch = new Child();
        }
    }
    class Parent{
        static String name1 = "hello";
        static{
            System.out.println("Parent static block");
        }
        public Parent(){
            System.out.println("Parent construct block");
        }
    }
    class Child extends Parent{
        static String name2 = "hello";
        static{
            System.out.println("Child static block");
        }
        public Child(){
            System.out.println("Child construct block");
        }
    }

    结果:

    结果分析:

    1. 明先初始化父类的静态属性在执行自己的静态属性,再是父类的构造方法再是自己的构造方法。

    2. 实例化 Child 类。第一要初始化类Child ,因为Child拥有父类(会判断父类是否初始化),类的初始化只有一次。。初始化类(就是按照顺序加载静态变量与静态方法)。

    3. 初始化Child后。开始实例化Child ,因为拥有父类,所以调用构造方法之前会调用父类的默认构造方法。

    代码5:

    public class Animal {
    	private static int k;
    	static{
    		System.out.println("父类的静态方法");
    	}
    	{
    		System.out.println("执行父类的构造代码块");
    	}
    	public Animal(){
    		System.out.println("执行父类的构造方法");
    	}
    	public static void main(String[] args) {
    		System.out.println(Animal.k);
    	}
    }
    

      运行结果:

    父类的静态方法
    0

    结果分析:
    1. 构造代码块与构造方法对于类的加载 没有关系。

    代码6:

    public class Animal {
        private static int k;
        {
            System.out.println("执行父类的构造代码块");
        }
        static{
            System.out.println("父类的静态方法");
        }
        public Animal(){
            System.out.println("执行父类的构造方法");
        }
        public static void main(String[] args) {
            Animal animal1 = new Animal();
            Animal animal2 = new Animal();
        }
    }

    结果:

    结果分析:

    1. 构造代码块至于构造方法相关,随着构造方法的执行而执行。

    代码7:

    public class Cat {
        private static int a;
        private static int b = 1000;
        static{
            a = 100;
            b = 200;
        }
        
        public static void main(String[] args) {
            System.out.println(Cat.a);
            System.out.println(Cat.b);
        }
    }

    结果分析:

    1. 可以把静代码块中的内容 看做是赋予操作。 

    2.  当静态代码块在a,b前面。此时输出的结果是100 1000

    代码8:

    package com.fande.amazon.ws.member.rs;
    class A {
        static {
            System.out.println("A的静态块");
        }
        private static String staticStr = getStaticStr();
        private String str = getStr();
        {
            System.out.println("A的实例块");
        }
        public A() {
            System.out.println("A的构造方法");
        }
        private static String getStaticStr() {
            System.out.println("A的静态属性初始化");
            return null;
        }
        private String getStr() {
            System.out.println("A的实例属性初始化");
            return null;
        }
        public static void main(String[] args) {
            new B();
            new B();
        }
    
    }
    class B extends A{
        private static String staticStr = getStaticStr();
        static {
            System.out.println("B的静态块");
        }
        {
            System.out.println("B的实例块");
        }
        public B() {
            System.out.println("B的构造方法");
        }
        private String str = getStr();
        private static String getStaticStr() {
            System.out.println("B的静态属性初始化");
            return null;
        }
        private String getStr() {
            System.out.println("B的实例属性初始化");
            return null;
        }
    }

    通过上面的分析,结果应该很明确了:

    总结:

    由此可见,实例化子类的时候,若此类未被加载过,首先加载是父类的类对象,然后加载子类的类对象,接着实例化父类,最后实例化子类,若此类被加载过,不再加载父类和子类的类对象。

    接下来是加载顺序,当加载类对象时,首先初始化静态属性,然后执行静态块;当实例化对象时,首先执行构造块(直接写在类中的代码块),然后执行构造方法。至于各静态块和静态属性初始化哪个些执行,是按代码的先后顺序。属性、构造块(也就是上面的实例块)、构造方法之间的执行顺序(但构造块一定会在构造方法前执行),也是按代码的先后顺序。

    参考:

    http://www.cnblogs.com/maowh/p/3729971.html

    http://blog.sina.com.cn/s/blog_68117d6d0102uzbq.html

  • 相关阅读:
    Mono项目将继续推动基于Linux的开发
    VS.PHP 在Visual Studio 下的 PHP 开发 IDE 工具
    SQL Server 2008 的代码提示功能
    想做的时候没有机会了
    我的最爱
    双缓冲
    做个好男人!
    再见了,曾经喜欢过的歌手
    看看他是喜欢你还是爱你的~~~
    独家:未来五年程序员应当具备的十项技能
  • 原文地址:https://www.cnblogs.com/chihirotan/p/6043442.html
Copyright © 2020-2023  润新知