java类初始化顺序
2017-07-04 09:40
204 查看
转载请注明出处:http://blog.csdn.net/mr_leixiansheng/article/details/74280154
一个Java类中会定义各种变量、方法和代码块。其中方法和代码块从存在的意义上来讲,都是为了操作这些变量的。所以就笔者个人理解,类的主体该是变量,方法和代码块是为变量而存在的。
变量值的改变有两种情形,一是在进行初始化的时候,而是在方法中对其进行操作的时候。变量值改变的先后顺序将直接影响到程序运行的正确与否,所以理正确理解变量值在Java中如何改变对于一个优秀码农来说,显得尤为重要。就以上两种改变变量值的情形来说,第二种情形比较直观,即方法何时调用,便何时改变相应变量值。当然,其中的特殊方法——构造器除外。构造器可以认为是一种特殊的初始化过程,但由于其特殊性,其初始化过程又必须单独考虑。
本文主要以包括“构造器”在内的一些初始化操作对变量值改变的先后顺序为线索,进行了一些代码实验和思考。
由于该主题的情况较复杂,笔者打算先从几个点出发,讨论变量值改变的先后顺序,最后再将这些点中的情况进行一个统一的讨论。
一、先初始化静态(static)变量,再初始化非静态变量。
其中涉及到类的加载机制,因为静态变量是在类加载的过程中便开辟空间,而非静态变量在实例化对象的时候才会开辟空间,具体代码实验如下:
[java]
view plain
copy
print?
class A
{
int y=printInit("non-static");
static int x= printInit("static");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class InitSequStatic
{
public static void main(String[] args)
{
A a= new A();
}
}
其运行结果如下:
可以发现,尽管A类中的非静态变量先于静态变量定义,但在初始化的过程中(准确来说是类的加载和对象的实例化过程中),静态变量先于非静态变量。这一点,我们在类继承中将会理解得更加清楚
二、对于有类继承关系的代码中,先初始化(加载)父类静态变量,然后初始化(加载)子类静态变量,继而初始化父类非静态变量,调用父类构造器,最后初始化子类非静态变量,调用子类构造器。
若存在多重继承关系,也同理。之所以此处静态变量“初始化”后面的括号中有“加载”一词,是因为静态变量在类加载的过程中首先会进行默认初始化,但非静态变量在对象实例化的过程中就不会进行默认初始化。此处需要提及:初始化分为默认初始化、显示初始化、构造代码块初始化和构造函数初始化,这将在第三点“初始化过程”中具体提及。
以下图为例:
先依次初始化(加载)A类、B类和C类的静态变量,再依次初始化A类的非静态变量,调用A类的构造器;然后依次初始化B类的非静态变量,调用B类的构造器;最后依次初始化C类的非静态变量,调用C类的构造器。具体代码实验如下:
[java]
view plain
copy
print?
class A
{
A()
{
System.out.println("A constructor");
}
static int ax=printInit("A static");
int ay=printInit("A nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class B extends A
{
B()
{
System.out.println("B constructor");
}
static int bx=printInit("B static");
int by=printInit("B nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class C extends B
{
C()
{
System.out.println("C constructor");
}
static int cx=printInit("C static");
int cy=printInit("C nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
public static void main(String[] args)
{
C c=new C();
}
}
其运行结果如下:
一个Java类中会定义各种变量、方法和代码块。其中方法和代码块从存在的意义上来讲,都是为了操作这些变量的。所以就笔者个人理解,类的主体该是变量,方法和代码块是为变量而存在的。
变量值的改变有两种情形,一是在进行初始化的时候,而是在方法中对其进行操作的时候。变量值改变的先后顺序将直接影响到程序运行的正确与否,所以理正确理解变量值在Java中如何改变对于一个优秀码农来说,显得尤为重要。就以上两种改变变量值的情形来说,第二种情形比较直观,即方法何时调用,便何时改变相应变量值。当然,其中的特殊方法——构造器除外。构造器可以认为是一种特殊的初始化过程,但由于其特殊性,其初始化过程又必须单独考虑。
本文主要以包括“构造器”在内的一些初始化操作对变量值改变的先后顺序为线索,进行了一些代码实验和思考。
由于该主题的情况较复杂,笔者打算先从几个点出发,讨论变量值改变的先后顺序,最后再将这些点中的情况进行一个统一的讨论。
一、先初始化静态(static)变量,再初始化非静态变量。
其中涉及到类的加载机制,因为静态变量是在类加载的过程中便开辟空间,而非静态变量在实例化对象的时候才会开辟空间,具体代码实验如下:
[java]
view plain
copy
print?
class A
{
int y=printInit("non-static");
static int x= printInit("static");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class InitSequStatic
{
public static void main(String[] args)
{
A a= new A();
}
}
class A { int y=printInit("non-static"); static int x= printInit("static"); private static int printInit(String s) { System.out.println(s); return 1; } } class InitSequStatic { public static void main(String[] args) { A a= new A(); } }
其运行结果如下:
可以发现,尽管A类中的非静态变量先于静态变量定义,但在初始化的过程中(准确来说是类的加载和对象的实例化过程中),静态变量先于非静态变量。这一点,我们在类继承中将会理解得更加清楚
二、对于有类继承关系的代码中,先初始化(加载)父类静态变量,然后初始化(加载)子类静态变量,继而初始化父类非静态变量,调用父类构造器,最后初始化子类非静态变量,调用子类构造器。
若存在多重继承关系,也同理。之所以此处静态变量“初始化”后面的括号中有“加载”一词,是因为静态变量在类加载的过程中首先会进行默认初始化,但非静态变量在对象实例化的过程中就不会进行默认初始化。此处需要提及:初始化分为默认初始化、显示初始化、构造代码块初始化和构造函数初始化,这将在第三点“初始化过程”中具体提及。
以下图为例:
先依次初始化(加载)A类、B类和C类的静态变量,再依次初始化A类的非静态变量,调用A类的构造器;然后依次初始化B类的非静态变量,调用B类的构造器;最后依次初始化C类的非静态变量,调用C类的构造器。具体代码实验如下:
[java]
view plain
copy
print?
class A
{
A()
{
System.out.println("A constructor");
}
static int ax=printInit("A static");
int ay=printInit("A nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class B extends A
{
B()
{
System.out.println("B constructor");
}
static int bx=printInit("B static");
int by=printInit("B nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
class C extends B
{
C()
{
System.out.println("C constructor");
}
static int cx=printInit("C static");
int cy=printInit("C nontatic");
private static int printInit(String s)
{
System.out.println(s);
return 1;
}
public static void main(String[] args)
{
C c=new C();
}
}
class A { A() { System.out.println("A constructor"); } static int ax=printInit("A static"); int ay=printInit("A nontatic"); private static int printInit(String s) { System.out.println(s); return 1; } } class B extends A { B() { System.out.println("B constructor"); } static int bx=printInit("B static"); int by=printInit("B nontatic"); private static int printInit(String s) { System.out.println(s); return 1; } } class C extends B { C() { System.out.println("C constructor"); } static int cx=printInit("C static"); int cy=printInit("C nontatic"); private static int printInit(String s) { System.out.println(s); return 1; } public static void main(String[] args) { C c=new C(); } }
其运行结果如下:
相关文章推荐
- java类初始化顺序-阿里笔试题
- 关于java类初始化的顺序
- java类的初始化和对象的创建顺序
- java类中元素初始化顺序
- java类中元素初始化顺序详解
- java类的初始化顺序
- java类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
- java类的加载以及初始化顺序
- Java类成员变量的初始化顺序
- Java类中的初始化顺序二
- java类的成员初始化顺序和初始化块知识
- java类初始化顺序
- Java类及对象初始化的顺序
- Java类的成员初始化顺序
- Java类中变量初始化、方法调用的顺序
- Java类的初始化顺序
- java类的初始化顺序
- java类的初始化顺序
- java类初始化顺序的影响
- java类的成员初始化顺序和初始化块顺序