1.直接new,调用了构造器
2.通过clone(),没有调用构造器
3.通过反射,调用了构造器
4.通过反序列化,没有调用构造器
5.通过Unsafe类的allocateInstance()方法,没有调用构造器
public class CreateByNew { public CreateByNew() { System.out.println("调用了构造..."); } public static void main(String[] args) { CreateByNew c1 = new CreateByNew(); CreateByNew c2 = new CreateByNew(); System.out.println(c1 == c2);//false } }
输出:
调用了构造... 调用了构造... false
需要实现Cloneable接口,可分为深克隆和浅克隆。clone()后的新对象会复制原对象的属性,但是并不会调用构造函数。
public class CreateByClone implements Cloneable { public int temp; public CreateByClone() { System.out.println("调用了构造.."); } public static void main(String[] args) throws CloneNotSupportedException { CreateByClone c1 = new CreateByClone(); c1.temp = 222; CreateByClone c2 = (CreateByClone) c1.clone(); System.out.println(c2.temp); System.out.println(c1 == c2); } }
输出:
调用了构造.. 222 false
反射创建对象:
class.newInstance():调用了无参构造
获取对应的Constructor,调用constructor的newInstance(),调用对应构造函数创建对象
public class CreateByReflection { private int temp; public int getTemp() { return temp; } public CreateByReflection() { System.out.println("调用了空参构造..."); } public CreateByReflection(int temp) { this.temp = temp; System.out.println("调用了带参构造..."); } public static void main(String[] args) throws Exception { Class clazz = CreateByReflection.class; //通过无参构造反射创建 CreateByReflection c1 = (CreateByReflection) clazz.newInstance(); //通过带参构造反射创建 Constructor constructor = clazz.getDeclaredConstructor(int.class); CreateByReflection c2 = (CreateByReflection) constructor.newInstance(10); System.out.println(c2.getTemp()); System.out.println(c1 == c2); } }
输出:
调用了空参构造... 调用了带参构造... 10 false
需要被序列化的对象实现Serializable接口,不会调用构造,反序列化回来的对象的属性值与序列化之前一致,但是是一个新对象。
public class CreateBySerializable { public static void main(String[] args) { Person p1 = new Person("二狗", 18); writeObject(p1); Person p2 = readObjcet(); System.out.println(p2); System.out.println(p1 == p2); } public static void writeObject(Person person) { FileOutputStream fileOut = null; ObjectOutputStream out = null; try { fileOut = new FileOutputStream("person.txt"); out = new ObjectOutputStream(fileOut); out.writeObject(person); System.out.println("Serialized data is saved"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } try { fileOut.close(); } catch (IOException e) { e.printStackTrace(); } } } public static Person readObjcet() { Person temp = null; FileInputStream fileIn = null; ObjectInputStream in = null; try { fileIn = new FileInputStream("person.txt"); in = new ObjectInputStream(fileIn); temp = (Person) in.readObject(); System.out.println("Deserialized Person..."); return temp; } catch (Exception e) { e.printStackTrace(); return null; }finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } try { fileIn.close(); } catch (IOException e) { e.printStackTrace(); } } } } class Person implements Serializable { public Person() { System.out.println("调用了空参构造..."); } public Person(String name, int age) { this.name = name; this.age = age; System.out.println("调用了带参构造..."); } public String name; public int age; @Override public String toString() { return "Person{" + "name='" + name + '/'' + ", age=" + age + '}'; } }
输出:
调用了带参构造... Serialized data is saved Deserialized Person... Person{name='二狗', age=18} false
Unsafe类通过native方法直接操作内存分配空间,创建对象。此时对象并没有执行构造,只是在内存中分配了空间,所有属性此时都是对应类型的0值。而且该对象并不被JVM管理,需要我们自己回收。
Unsafe类的构造为私有,且通过@CallerSensitive方法保证只有BootStrap类加载器加载的类才可以调用Unsafe类中的方法。
所以只能通过反射获取Unsafe类实例。
public class CreateByUnsafe { public static void main(String[] args) throws Exception { //基于反射获取Unsafe实例 Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); People p1 = (People) unsafe.allocateInstance(People.class); People p2 = (People) unsafe.allocateInstance(People.class); p1.age = 18; System.out.println(p1); System.out.println(p1 == p2); //返回成员变量在内存中的地址相对于对象内存地址的偏移量 Field f = People.class.getDeclaredField("age"); long offset = unsafe.objectFieldOffset(f); System.out.println(offset);//12 // markword:8bytes(64bits) + class pointer:4bytes(32bits) == 12 bytes } } class People { public int age; @Override public String toString() { return "People{" + "age=" + age + '}'; } }
输出:
People{age=18} false 12