面试阿里,字节跳动,华为必须知道的Java创建对象的5种方式

Java创建对象的5种方式

1.直接new,调用了构造器
2.通过clone(),没有调用构造器
3.通过反射,调用了构造器
4.通过反序列化,没有调用构造器
5.通过Unsafe类的allocateInstance()方法,没有调用构造器

1. 直接new

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

  

2. 通过clone()

需要实现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

  

3. 通过反射

反射创建对象:

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

  

4. 反序列化创建对象

需要被序列化的对象实现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

  

5. 通过Unsafe类

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

  

 

上一篇:react:reducer-creator


下一篇:注册表REG文件编写大全