java类中包含静态成员、方法时的打印顺序
2008-03-26 16:16
429 查看
在java中,当静态和非静态、继承组合起来时,程序的执行顺序就容易使人困惑了,尤其是某些BT公司特别喜欢出这种题目来考验java功底。本文旨在这种组合中通过打印语句来理清思路。
先看下例子:请先试着写出打印的结果:)
class Base...{
static...{
System.out.println("{父类加载}");
}
static int a=getValue("静态:获取父类a值");
Base()...{
System.out.println("调用父类无参构造函数,现打印父类a赋值结果:"+a);
a++;
printA();
}
...{
System.out.println("{父类实例初始代码块}");
}
Base(String s)...{
System.out.println("父类带参构造函数"+s);
}
void printA()...{
System.out.println("父类赋值结果a="+a);
}
static int getValue(String s)...{
System.out.println("静态:父类原始a="+a);
System.out.println(s);
return ++a;
}
}
public class Child extends Base...{
static...{
System.out.println("{子类加载}");
}
static Child child=new Child();
static int a=getValue("静态:获取子类a值");
Child()...{
System.out.println("调用子类无参构造函数,现打印子类a赋值结果:"+a);
a++;
printA();
}
...{
System.out.println("{子类实例初始代码块}");
}
Child(String s)...{
System.out.println("子类带参构造函数"+s);
}
void printA()...{
System.out.println("子类赋值结果a="+a);
}
static int getValue(String s)...{
System.out.println("静态:子类原始a="+a);
System.out.println(s);
return ++a;
}
public static void main(String[] args)...{
//new Child("实例化子类");
new Child();
}
}
先看运行结果:
--------------------------------------------------------------------
{父类加载}
静态:父类原始a=0
静态:获取父类a值
{子类加载}
{父类实例初始代码块}
调用父类无参构造函数,现打印父类a赋值结果:1
子类赋值结果a=0
{子类实例初始代码块}
调用子类无参构造函数,现打印子类a赋值结果:0
子类赋值结果a=1
静态:子类原始a=1
静态:获取子类a值
{父类实例初始代码块}
调用父类无参构造函数,现打印父类a赋值结果:2
子类赋值结果a=2
{子类实例初始代码块}
调用子类无参构造函数,现打印子类a赋值结果:2
子类赋值结果a=3
-------------------------------------------------------------------
例子中有如下几处刻意设计的难点:
1.父子类都有同名变量a,考察静态变量在继承中的表现;
2.静态成员child在初始化时即被实例化,先于静态变量a的赋值,考察a的赋值顺序;
3.静态代码块和实例代码块的区别;
4.printA()是实例方法,考察当实例化子类时,在父类构造方法中调用实例方法是否有多态;
分析:
1.继承顺序:当实例化子类时,会先加载父类,并给父类的静态变量分配空间和自动初始化,其值和实例变量初始化值相同,初始化时可以调用静态方法;然后才加载子类,并给子类的静态变量分配空间,此时如果静态的类成员需要实例化,则调用子类构造方法。而进入子类构造方法时,最先调用super(),所以进入父类无参构造方法,此时调用的实例方法一定是子类重写的方法,因为堆中只有子类的实例方法。
2.初始化顺序:当静态的类成员和静态的基本变量同时初始化时,其先后顺序取决于语句顺序。
3.实例代码块仅当构造方法中调用super()之后才被调用,每次实例化都会被调用一次;而静态代码块则只在类被第一次加载时调用,且只运行一次。
4.静态变量:静态变量属于类,存在于代码区,内存中只有1份,为所有实例共享,任何实例对其修改都会影响到它的值。
5.语句顺序:
static Child child=new Child();
static int a=getValue("静态:获取子类a值");
注意这里的顺序导致了子类加载之后立即在堆中实例化了一个child对象,而在代码区中并未执行到静态变量a的声明,即:
static int a=getValue("静态:获取子类a值");
故先后出现父子类构造函数的打印语句,然后才是"静态:获取子类a值"。
先看下例子:请先试着写出打印的结果:)
class Base...{
static...{
System.out.println("{父类加载}");
}
static int a=getValue("静态:获取父类a值");
Base()...{
System.out.println("调用父类无参构造函数,现打印父类a赋值结果:"+a);
a++;
printA();
}
...{
System.out.println("{父类实例初始代码块}");
}
Base(String s)...{
System.out.println("父类带参构造函数"+s);
}
void printA()...{
System.out.println("父类赋值结果a="+a);
}
static int getValue(String s)...{
System.out.println("静态:父类原始a="+a);
System.out.println(s);
return ++a;
}
}
public class Child extends Base...{
static...{
System.out.println("{子类加载}");
}
static Child child=new Child();
static int a=getValue("静态:获取子类a值");
Child()...{
System.out.println("调用子类无参构造函数,现打印子类a赋值结果:"+a);
a++;
printA();
}
...{
System.out.println("{子类实例初始代码块}");
}
Child(String s)...{
System.out.println("子类带参构造函数"+s);
}
void printA()...{
System.out.println("子类赋值结果a="+a);
}
static int getValue(String s)...{
System.out.println("静态:子类原始a="+a);
System.out.println(s);
return ++a;
}
public static void main(String[] args)...{
//new Child("实例化子类");
new Child();
}
}
先看运行结果:
--------------------------------------------------------------------
{父类加载}
静态:父类原始a=0
静态:获取父类a值
{子类加载}
{父类实例初始代码块}
调用父类无参构造函数,现打印父类a赋值结果:1
子类赋值结果a=0
{子类实例初始代码块}
调用子类无参构造函数,现打印子类a赋值结果:0
子类赋值结果a=1
静态:子类原始a=1
静态:获取子类a值
{父类实例初始代码块}
调用父类无参构造函数,现打印父类a赋值结果:2
子类赋值结果a=2
{子类实例初始代码块}
调用子类无参构造函数,现打印子类a赋值结果:2
子类赋值结果a=3
-------------------------------------------------------------------
例子中有如下几处刻意设计的难点:
1.父子类都有同名变量a,考察静态变量在继承中的表现;
2.静态成员child在初始化时即被实例化,先于静态变量a的赋值,考察a的赋值顺序;
3.静态代码块和实例代码块的区别;
4.printA()是实例方法,考察当实例化子类时,在父类构造方法中调用实例方法是否有多态;
分析:
1.继承顺序:当实例化子类时,会先加载父类,并给父类的静态变量分配空间和自动初始化,其值和实例变量初始化值相同,初始化时可以调用静态方法;然后才加载子类,并给子类的静态变量分配空间,此时如果静态的类成员需要实例化,则调用子类构造方法。而进入子类构造方法时,最先调用super(),所以进入父类无参构造方法,此时调用的实例方法一定是子类重写的方法,因为堆中只有子类的实例方法。
2.初始化顺序:当静态的类成员和静态的基本变量同时初始化时,其先后顺序取决于语句顺序。
3.实例代码块仅当构造方法中调用super()之后才被调用,每次实例化都会被调用一次;而静态代码块则只在类被第一次加载时调用,且只运行一次。
4.静态变量:静态变量属于类,存在于代码区,内存中只有1份,为所有实例共享,任何实例对其修改都会影响到它的值。
5.语句顺序:
static Child child=new Child();
static int a=getValue("静态:获取子类a值");
注意这里的顺序导致了子类加载之后立即在堆中实例化了一个child对象,而在代码区中并未执行到静态变量a的声明,即:
static int a=getValue("静态:获取子类a值");
故先后出现父子类构造函数的打印语句,然后才是"静态:获取子类a值"。
相关文章推荐
- java类中包含静态成员、方法时的打印顺序
- Java类的各种成员初始化顺序如:父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺序
- java中 静态成员、实例成员、构造方法在子类和父类中的执行顺序
- java中类的静态代码块、构造代码块、构造方法、静态成员的初始化顺序详解
- java中类的静态代码块、构造代码块、构造方法、静态成员的初始化顺序详解
- java静态成员初始化顺序
- Java中静态代码块,非静态代码块,以及父类与子类的构造方法的之间调用顺序
- java静态代码块、构造方法、构造块的执行顺序
- Java初学者Paulmarkyes---中静态代码块,普通代码块,构造代码块,构造方法先后执行顺序以及区别
- java 父类子类静态成员,实例成员,构造函数初始化的顺序
- java静态代码块、初始化块和构造方法的执行顺序
- 关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨
- java静态方法,静态变量,初始化顺序
- Java类中代码的执行顺序 静态代码块>构造代码块>构造方法
- Java 构造方法和成员变量初始化顺序
- Java静态方法,静态变量,初始化顺序
- Java类的各种成员初始化顺序如:父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺序
- Java父类、子类、静态成员和普通成员初始化的顺序
- Java静态方法,静态变量,初始化顺序
- java 静态代码块和构造方法执行优先顺序