一、创建对象过程
1、检测类是否被加载
创建一个Java对象时,JVM首先会检查这个new指令的参数能否在常量池中定位到一个类的符号引用,然后检查与这个符号引用相对应的类是否已经成功经历加载、解析和初始化等步骤。如果没有,那必须先执行相应的类加载过程。
2、为新生对象分配内存
当类完成装载步骤之后,就已经完全确定出创建对象实例时所需的内存空间大小,接下来JVM将会对其进行内存分配,以存储所生成的对象实例。在堆中为其开辟内存空间, 在栈中分配一块内存存储变量即引用, 这个变量指向堆内存中得值
3、初始化零值
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
4、进行必要的设置
接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。
5、执行init方法
在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java程序的视角来看,对象创建才刚开始,方法还没有执行,所有的字段都还为零。所以一般来说,执行new指令之后会接着执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。
二、Java中创建对象的四种方式:
1、new关键字调用构造函数:
这是我们最常见的也是最简单的创建对象的方式,通过构造函数创建实例。
User user=new User();//无参构造器
User user=new User(id,uname,password);//有参构造器
-
2、反射方法
- Class.newInstance方法(只能调用无参构造器)
User user = (User)Class.forName("com.wjj.test.User").newInstance();//forName里面是这个类所在的路径
- Constructor.newInstance方法调用构造器创建对象(可以调用无参和有参的构造器)。
Constructor<User> constructor = User.class.getDeclaredConstructor(int.class,String.class,String.class); //如果是无参则参数为null就行
User user = (User) constructor.newInstance(1,"小明","password");
事实上Class的newInstance方法内部调用Constructor的newInstance方法。
-
3、Clone方法:
无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。要使用clone方法,我们必须先实现Cloneable接口并实现其定义的clone方法。
User user2 = <User>user.clone();//前提是要有一个user对象
-
4、反序列化方法:
当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口。如:
ObjectInputStream in = new ObjectInputStream (new FileInputStream("data.obj")); //data.obj文件是我们在序列化的时候,将流存入该文件中。此时将它反序列化出来。
User user = (User)in.readObject();