class类的初始化

class类的初始化##

 C++中引入了构造器这个概念(constructor)的概念,这是在创建一个对象时被自动调用的特殊方法。
 Java也引入了构造器
 构造器的主要的作用就是确保每个对象都会得到初始化。创建对象时,如果其类具有构造器,Java就会在用户操作对象之前自动调用相应的构造器,从而确保初始化的进行。



public class Initial extends Parent {
	public static int i=j+1;
	public Initial()
	{
		System.out.println("1");
		System.out.println(i);
	}
	public  void get()
	{
		super.get();
		System.out.println("4");
	}
}
class Parent 
{
	public static int j=4;
	public Parent()
	{
		System.out.println("2");
	}
	public  void get()
	{
		System.out.println("3");
	}
}
...
public static void main(String[] args) {
		// TODO Auto-generated method stub
		Initial initial=new Initial();
		initial.get();
}
...

在上面类Initial和Parent类各有一个不带参数的构造器,这可以保证在使用对象之前,已经被初始化了
 由于构造器和类名必须完全相同,所以不用在遵从方法首字母小写的编码风格

    Initial initial=new Initial();

 如果Initial()是Initial类的唯一的构造器,那么编译器不会允许其他任何方式创建Initial对象。new Initial()会给相应的对象分配空间,并返回对新建对象的引用
 不带任何参数的构造器被称为默认构造器。

默认构造器###

 默认构造器又称为无参构造器,它的作用是创建一个默认对象。如果类中没有构造器,则编译器会自动创建一个默认构造器。

public Bird(){} 
...
public static void main(String[] args) {
    Bird bird=new Bird();
}
...

如果已经定义了一个构造器(无论是否有参数),编译器不会再自动创建默认构造器.意思就是,如果定义了构造器,那么只能用已经定义的构造器来构造对象,不能再使用默认构造器了。

继承和初始化####

 在思考这个问题时,就要考虑到类的加载先后顺序。Java的加载方式不同于C++。Java中的所有事物都是对象。每个类的编译代码都存在自己的独立文件里。该文件只在需要使用程序代码时才会被加载。一般来说,类的代码在初次使用才会加载。这通常指的是加载发生于创建类的第一个对象,但是当访问static域或static方法时,也会发生加载。(构造器是没有显式使用static的静态方法),因此在使用构造器创建对象时就会加载类。
 运行最上面的代码时,代码的入是main()函数,由于main()函数是静态函数,所以加载main函数所在的类的编译代码。接下来是Initial initial=new Initial();创建Initial对象,需要加载Initial类的编译代码(Initial.class).在对它进行加载的过程中编译器会发现它有一个基类,于是继续进行加载。如果该基类还有其他基类,则第二个基类就会被加载,如此类推,根基类的static初始化会被执行,然后是下一个导出类,以此类推。这种方式很重要,因为导出类的static的初始化可能会依赖基类成员能否被正确的初始化

类中成员的初始化###

 类加载的顺序以及继承类之间的static初始化顺序现在清楚了,但是在一个类之中的初始化顺序是怎么样的?

class  Dogs
{
	int a;
	boolean b;
	char c;
	float f;
	double d;
	Dogs dogs;
	public void PrintInf()
	{
		System.out.println("a  "+a);
		System.out.println("b  "+b);
		System.out.println("c  "+c);
		System.out.println("d  "+d);
		System.out.println("dogs   "+dogs);
	}
	public Dogs(int i)
	{
		System.out.println("Dog("+i+")");
	}
	public Dogs()
	{
		
	}
}
class  Dogss{
	Dogs dogs=new Dogs(0);
	static Dogs dogs1=new Dogs(1) ;
	public Dogss()
	{
		System.out.println("Dogss()");
		dogs3=new Dogs(33);
	}
	static Dogs dogs2=new Dogs(2);
	static Dogs dogs3=new Dogs(3);
}
public class Dog {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dogss dogss=new Dogss();
		new Dogs().PrintInf();
	}

}


运行结果
Dog(1)
Dog(2)
Dog(3)
Dog(0)
Dogss()
Dog(33)
a  0
b  false
c  
d  0.0
dogs   null
 

上面这些代码可以看出
1、首先关于基本类型的初始化可以发现,在构造对象之后,基本类型数据成员都会首先初始化一个默认值,没有自定义初始化的对象会默认为null。如上面的dogs被默认为null。
2、其次在类的内部,加载时首先是先初始化静态变量,然后初始化正常对象(这里重点说明一下,不是static的基本类型变量,在没有使用构造器创建对象时是没有存储位置的,所以也不会先于构造器初始化),然后调用构造器。就如同上面的结果一样。先初始化了Dog(1),Dog(2),Dog(3),然后接下来是正常变量Dog(0),最后才是构造器
 加载类之后,先初始化静态变量(对象和基本类型数据),接下来初始化正常创建的对象,(要使用构造器的话,因为只使用静态参数的话是不需要使用构造器的)接下来调用构造器,初始化基本类型数据为默认值,调用自定义基本数据初始化方法,最后调用构造器里面的内容

总结一下对象的创建过程,假设有个名为Dog的类

1.即使没有显式使用static关键字,构造器也是静态方法。因此当第一次创建Dog的对象时,或者Dog类的静态方法被首次访问时,Java解释器就会加载Dog类,即寻找Dog.class文件

2.然后载入Dog.class文件,这是有关静态初始化的所有动作都会执行(比如静态变量被初始化,静态对象的初始化,静态方法的初始化)。因此静态初始化只会在Class对象被首次加载的时候进行一次

3.当用new Dog()创建对象的时候,首先在堆上为Dog对象分配足够的存储空间。

4.这块存储空间现在为空,自动将Dog对象中的基本类型数据都设置为默认值,引用被设置为null

5.执行所有出现在字段定义出的初始化动作

6.执行构造器

原文地址:https://www.cnblogs.com/Black-Cobra/p/6896932.html