问题与思考3
静态初始化块的执行顺序是:
先初始化父类(最高层次的)的静态初始化块,父类的无参构造器,在进行子类的静态初始化块,子类的无参构造器;
然后是父类的普通初始化块,子类的普通初始化块;父类的带参构造器,子类的带参构造器。
静态初始化块只执行一次。 创建子类型的对象时,也会导致父类型的静态初始化块的执行。
////可以查询创建了多少个类
public class Test{
public static void main( String args[]){
Test a= new Test();
a.OutputInformation();
Test b= new Test();
b.OutputInformation();
Test c= new Test();
c.OutputInformation();
Test d= new Test();
d.OutputInformation();
}
static int num=0;
public Test(){
num++;
}
public void OutputInformation(){
System.out.println("已经创建了"+num+"个对象!");
}
}
思考:
一、对象变量也可以直接使用“==”判等吗?
运行以下代码将得到什么结果
运行结果
对象变量在比较是比较多是两个变量的地址,所以无法对两个变量内容直接进行比较,但是可以重写调用基类中的equals();方法。
一、以下代码无法编译,哪里出错了
运行结果
未定义函数Foo();如果类提供了一个自定义的构造方法,将导致系统不再提供默认构造方法。
三、如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
运行结果
可以在类中使用“{”和“}”将语句包围起来,直接将其作为类的成员。类的这种“没有名字”的“成员”,多用于初始化类的字段。
1)所有类的变量都默认初始化null,数字类的原始数据类型默认初始化为0。
2)执行类成员定义的默认值或初始化块,优先于最新的那个,如上式的100。
3)执行类的构造函数,有多个构造函数,通过参数区分执行,创建类的对象时,就会立即执行。因此,适合于封装那些“对象创建时必须执行的代码”。
四、请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
运行结果
- 所有的静态初始化块都优先执行,其次才是非静态的初始化块和构造函数,它们的执行顺序是:
- 父类的静态初始化块
- 子类的静态初始化块
- 父类的初始化块
- 父类的构造函数
- 子类的初始化块
- 子类的构造函
静态初始化块的输出只出现了一次,也就是说每个类的静态初始化块都只在第一次实例化该类对象时执行一次。
五、
如何在静态方法中访问类的实例成员?
public class Example
{
int x = 3;//类的实例变量,初始化值为3
static int y = 4;//类的静态变量,初始化值为4
public static void method()//静态方法
{
System.out.println("实例变量x = " + new Example().x);//在静态方法中访问类的实例变量需首先进行类的实例化
System.out.println("静态变量y = " + y);//在静态方法中可直接访问类的静态变量
}
public static void main(String[] args)
{
Example.method();
Example ex = new Example();
System.out.println("x = " + ex.x);
}
}
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制