面試阿里,字節跳動,華爲必須知道的Java建立對象的5種方式

Java建立對象的5種方式

1.直接new,調用了構造器
2.經過clone(),沒有調用構造器
3.經過反射,調用了構造器
4.經過反序列化,沒有調用構造器
5.經過Unsafe類的allocateInstance()方法,沒有調用構造器java

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
    }}

輸出:bash

調用了構造...
調用了構造...
false

2. 經過clone()

須要實現Cloneable接口,可分爲深克隆和淺克隆。clone()後的新對象會複製原對象的屬性,可是並不會調用構造函數。app

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);
    }}

輸出:ide

調用了構造..
222
false

3. 經過反射

反射建立對象:函數

class.newInstance():調用了無參構造
獲取對應的Constructor,調用constructor的newInstance(),調用對應構造函數建立對象this

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);
    }}

輸出:spa

調用了空參構造...
調用了帶參構造...
10
false

4. 反序列化建立對象

須要被序列化的對象實現Serializable接口,不會調用構造,反序列化回來的對象的屬性值與序列化以前一致,可是是一個新對象。code

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 +
                '}';
    }}

輸出:orm

調用了帶參構造...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
相關文章
相關標籤/搜索