• 动手动脑 自信成就人生


    动手动脑自信成就人生

    动手动脑一

    以下代码输出结果是什么?请依据代码的输出结果,自行总结Java字段初始化的规律。并运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。

    猜一猜:200 300

    正确结果:100 300

    解释:

    Java进行初始化的地方有两个:初始化块和构造函数,其中初始化块又分为静态初始化块和实例初始化块。静态初始化块是类中由static修饰的初始化块,实例初始化块为类中没有任何关键字修饰的初始化语句。程序在定义一个类的对象之前要先将该类的class文件转载进内存,而class文件是编译后生成的,其中包括了类的初始化过程的定义,即Java 编译器把所有的类变量(静态变量)初始化语句和类型的静态初始化器通通收集到 <clinit> 方法内,该方法只能被 Jvm 调用,专门承担初始化工作。而class文件与类中的成员变量对应的是 "<init>()" 方法。编译器会为每一个构造函数生成一个 "<init>()" 方法。

    类的静态变量即类变量是在首次装载后完成初始化的,而且此过程只进行一次。而类的成员变量的初始化是在装载完成后创建该类的对象时进行的。由此可知,类的初始化顺序是先静态成员,而后是非静态成员。需要指出的是,不管是静态成员还是非静态成员的初始化,如果存在父类则要先进行父类的初始化,然后才是子类的初始化。初始化块跟定义时初始化是同等的关系,两者的先后顺序与在类中出现的先后有关。当初始化块跟定义时初始化都进行完后则进入构造函数。

    对于初始化顺序相同(即同为静态变量和静态初始化块或者同为非静态的)的成员变量,在初始化块中只能进行初始化而不能进行引用!

    1、执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”。

    2、执行类的构造函数。

    3、类的初始化块不接收任何的参数,而且只要一创建类的对象,它们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。

    4、当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行。

    综上,类的总的加载及初始化顺序为:静态变量--静态初始化块--静态方法--非静态变量--非静态初始化块--非静态方法--构造器。

    请自行编写示例代码验证以上结论。

    class Parent {

        public static String p_StaticField = "父类--静态变量";

        public String p_Field = "父类--变量";

        static {

            System.out.println(p_StaticField);

            System.out.println("父类--静态初始化块");

        }

        {

            System.out.println(p_Field);

            System.out.println("父类--初始化块");

        }

     

        public Parent() {

            System.out.println("父类--构造器");

        }

    }

     

    public class SubClass extends Parent {

        public static String s_StaticField = "子类--静态变量";

        public String s_Field = "子类--变量";

        // 静态初始化块

        static {

            System.out.println(s_StaticField);

            System.out.println("子类--静态初始化块");

        }

        {

            System.out.println(s_Field);

            System.out.println("子类--初始化块");

        }

     

        public SubClass() {

            System.out.println("子类--构造器");

        }

     

        public static void main(String[] args) {

            new Parent();

            System.out.println("-------------------");

            new SubClass();

            System.out.println("-------------------");

            new SubClass();

        }

    }

    运行结果:

    父类--静态变量

    父类--静态初始化块

    子类--静态变量

    子类--静态初始化块

    父类--变量

    父类--初始化块

    父类--构造器

    -------------------

    父类--变量

    父类--初始化块

    父类--构造器

    子类--变量

    子类--初始化块

    子类--构造器

    -------------------

    父类--变量

    父类--初始化块

    父类--构造器

    子类--变量

    子类--初始化块

    子类--构造器

    动手动脑二

    静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?

    请编写代码验证你的想法。

    类中静态的方法或者属性,本质上来讲并不是该类的成员,在java虚拟机装在类的时候,这些静态的东西已经有了对象,它只是在这个类中"寄居",不需要通过类的构造器(构造函数)类实现实例化;而非静态的属性或者方法,在类的装载是并没有存在,需在执行了该类的构造函数后才可依赖该类的实例对象存在。所以在静态方法中调用非静态方法时,编译器会报错。(不懂……)

    public class A{

    //类A中非静态方法

    public void func(){ ...... }

    //类A中静态方法(主函数)

    public static void main(String[] args){

    A a=new A();//需实例化A的对象后才可以调用A中非静态方法

    a.func();

    }

    动手动脑三

    使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数。请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”。

    class Jishu{

        private static int a;

        public Jishu()

        {

            a++;

        }

        public static int get()

        {

            return a;

        }

    }

    public class DuixiangNum {

    public static void main(String[] args){

        Jishu j1=new Jishu();

        Jishu j2=new Jishu();

        System.out.println("你已经创建了"+Jishu.get()+"个对象");

        }

    }

     

    动手动脑四

     

    两对整数明明完全一样,为何一个输出true,一个输出false

    (提示:使用javap来分析生成class文件,看它调用了Interger类的哪个方法,然后打开JDK源文件查看源码,就可以找到答案。)

    (看不懂)

  • 相关阅读:
    mysql 临时表
    mysql 日期类型计算
    mysql 报错:Every derived table must have its own alias
    mysql 查看解释计划的两种方式
    mysql 获取系统当前时间的3种方式
    [Typescript + React] Tip: Use generics in React to make dynamic and flexible components
    [Typescript] 44. Medium Drop char
    [Typescript] Tips: Use 'extends' keyword to narrow the value of a generic
    [Typescript] 42. Medium Remove Index Signature
    [RxJS] Defer task execution with the asapScheduler (microtask)
  • 原文地址:https://www.cnblogs.com/love528/p/4887989.html
Copyright © 2020-2023  润新知