动手动脑 自信成就人生

动手动脑自信成就人生

动手动脑一

以下代码输出结果是什么?请依据代码的输出结果,自行总结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源文件查看源码,就可以找到答案。)

(看不懂)

原文地址:https://www.cnblogs.com/love528/p/4887989.html