调用了构造函数
1)使用new关键字
2)使用Class类的newInstance方法:
a.使用Class类的forName方法
b.使用ClassLoader类的loadClass方法
3)使用Constructor类的newInstance方法
没有调用构造函数
1)使用clone方法
2)使用反序列化
这个是我们常用的创建对象的方式,通过new 类名()可以调用此类的构造函数(无参和有参)。这种方式,类的生命周期中的加载、初始化、实例化三个操作都会执行
Person person = new Person();
这三种newInstance方法就是大家所说的反射,可以归为一类。事实上Class的newInstance方法内部调用Constructor的newInstance方法。
我们也可以使用Class类的newInstance方法创建对象。这个newInstance方法调用无参的构造函数创建对象。
一)使用Class类的forName方法
Class c = Class.forName("类名"); // 加载、初始化
c.newInstance(); // 实例化
Class class1 = Class.forName("com.huang.class.Person ") ;
class1.newInstance();
或者
Person person2 = (Person) Class.forName("com.huang.class.Person").newInstance();
或者
Person person2 = Person.class.newInstance();
二)使用ClassLoader类的loadClass方法
Class c = ClassLoader.getSystemClassLoader() .loadClass("类名"); // 加载
c.newInstance();// 初始化 ---> 实例化
例如:
Class c = ClassLoader.getSystemClassLoader()
.loadClass("com.huang.class.Person "); // 加载
c.newInstance();// 初始化 ---> 实例化
三)使用Constructor类的newInstance方法创建对象
和Class类的newInstance方法很像, java.lang.reflect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个newInstance方法调用有参数的和私有的构造函数。这里需要强调一点private(私有的)修饰的属性或者方法并非绝对的安全,只是对开发者使用的一个约束。属性可以在set()方法中加入约束。
Constructor
Person person3 = constructor.newInstance();
调用一个对象的clone方法,clone方法所做的的操作是直接复制字段的内容,换句话说,这个操作并不管该字段对应的对象实例内容,jvm都会创建一个新同类型对象,将前面对象的内容全部拷贝进去。像这样字段对字段的拷贝(field to field copy)就成为"浅拷贝",clone方法所做的正是"浅拷贝"用clone方法创建对象构造函数不被自动调用。
JDK中Object# clone()方法的原型是:protected native Object clone() throws CloneNotSupportedException; 方法修饰符是protected,而不是public。这种访问的不可见性使得我们对Object#clone()方法不可见。所以,必需重写Object的clone方法后才能使用。
值得注意的是 :如果需要使用clone方法,必需实现java.lang.Cloneable接口,并实现其定义的clone方法。不实现Clonable接口就会抛出java.lang.CloneNotSupportedException。
Person person4 = (Person) person4.clone();
当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象。在反序列化时,jvm创建对象并不会调用任何构造函数。
为了反序列化一个对象,我们需要让我们的类实现Serializable接口
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Person person5 = (Person) in.readObject();
我们从上面的字节码片段可以看到,除了第1个方法,其他4个方法全都转变为invokevirtual(创建对象的直接方法),第一个方法转变为两个调用,new和invokespecial(构造函数调用)。