package com.xu.es.document.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author itmei
* @date 2023/5/25 21:48
* @description: 學(xué)生類
* @title: Student
* @package com.xu.es.document.entity
*/
@Data
public class Student implements Cloneable, Serializable {
public Student() {
}
public Student(int age) {
this.age = age;
}
private String id;
private int age;
private String name;
@Override
public Student clone() {
try {
return (Student) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
1 使用new關(guān)鍵字
這是最常見的創(chuàng)建對(duì)象的方式。使用 new 關(guān)鍵字,調(diào)用對(duì)象的構(gòu)造方法來創(chuàng)建一個(gè)新的實(shí)例。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) {
Student object = new Student(10);
System.out.println(JSONUtil.toJsonPrettyStr(object));
}
}
{
"age": 10
}
Process finished with exit code 0
2 使用Class類的newInstance()方法
Java中的每個(gè)類都有一個(gè)名為 Class 的類對(duì)象,可以使用它的 newInstance() 方法創(chuàng)建類的實(shí)例。這種方式要求類必須有一個(gè)無參的構(gòu)造方法。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) throws Exception {
Student object = Student.class.getDeclaredConstructor().newInstance();
System.out.println(JSONUtil.toJsonPrettyStr(object));
}
}
{
"age": 0
}
Process finished with exit code 0
3 使用Constructor類的newInstance()方法
Java的反射機(jī)制允許在運(yùn)行時(shí)動(dòng)態(tài)地獲取類的信息并操作類。通過 Class 類的 getConstructor() 和 newInstance() 方法可以創(chuàng)建對(duì)象。這種方式可以使用帶參的構(gòu)造方法。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) throws Exception {
Class<?> clazz = Student.class;
Student object = (Student) clazz.getDeclaredConstructor(int.class).newInstance(10);
System.out.println(JSONUtil.toJsonPrettyStr(object));
}
}
{
"age": 10
}
Process finished with exit code 0
4 使用clone()方法
需要實(shí)現(xiàn)Cloneable,對(duì)象拷貝是創(chuàng)建對(duì)象的一種方式,它通過復(fù)制一個(gè)已有對(duì)象的值來創(chuàng)建一個(gè)新的對(duì)象。被拷貝的類需要實(shí)現(xiàn) Cloneable 接口,并重寫 clone() 方法,淺clone()不會(huì)調(diào)用構(gòu)造方法。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) {
Student object = new Student(10);
Student object1 = object.clone();
System.out.println(JSONUtil.toJsonPrettyStr(object1));
}
}
{
"age": 10
}
Process finished with exit code 0
5 反序列化
需要實(shí)現(xiàn)Serializable,反序列化是將對(duì)象從字節(jié)流(如文件、網(wǎng)絡(luò)傳輸?shù)龋┺D(zhuǎn)換回內(nèi)存中的對(duì)象的過程。在進(jìn)行反序列化時(shí),Java會(huì)使用特定的機(jī)制創(chuàng)建對(duì)象,并將字節(jié)流中的數(shù)據(jù)填充到對(duì)象中。
反序列化創(chuàng)建對(duì)象的原理如下:
類加載:在進(jìn)行反序列化之前,Java需要加載類的定義。如果已加載的類與序列化數(shù)據(jù)中的類完全匹配,則直接使用已加載的類。否則,Java會(huì)嘗試根據(jù)序列化數(shù)據(jù)中的類名去加載類定義。
對(duì)象實(shí)例化:一旦類定義加載完成,Java使用類的構(gòu)造函數(shù)創(chuàng)建一個(gè)新的對(duì)象實(shí)例。通常情況下,會(huì)調(diào)用類的無參構(gòu)造函數(shù)來創(chuàng)建對(duì)象。如果類中沒有無參構(gòu)造函數(shù),或者無法訪問無參構(gòu)造函數(shù)(如私有構(gòu)造函數(shù)),則可能會(huì)導(dǎo)致反序列化失敗。
數(shù)據(jù)填充:在對(duì)象實(shí)例化后,Java將會(huì)將序列化數(shù)據(jù)中的字段值逐個(gè)填充到對(duì)象的對(duì)應(yīng)字段中。這個(gè)過程會(huì)使用反射來訪問對(duì)象的字段,并根據(jù)字段的類型和值進(jìn)行填充。
如果是文件可以使用FileInputStream和ByteArrayOutputStream的原理一樣。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) throws Exception {
Student object = new Student(10);
byte[] bytes = serialize(object);
Student object1 = (Student) deserialize(bytes);
System.out.println(JSONUtil.toJsonPrettyStr(object1));
}
private static byte[] serialize(Student object) throws Exception {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream oOut = new ObjectOutputStream(bOut);
oOut.writeObject(object);
return bOut.toByteArray();
}
private static Object deserialize(byte[] object) throws Exception {
ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(object));
return oIn.readObject();
}
}
{
"age": 10
}
Process finished with exit code 0
6 使用MethodHandles
Java MethodHandles是Java 7中引入的一種新的反射機(jī)制,它提供了對(duì)方法、字段和構(gòu)造函數(shù)的動(dòng)態(tài)訪問和調(diào)用。相比傳統(tǒng)的反射API,MethodHandles在性能和安全性方面都有所提升。
MethodHandles的原理可以簡要概括為以下幾個(gè)步驟:
獲取MethodHandle:首先,需要通過MethodHandles類的靜態(tài)方法來獲取MethodHandle對(duì)象。MethodHandle是一個(gè)對(duì)具體方法、字段或構(gòu)造函數(shù)的引用。
綁定方法接收者:MethodHandle對(duì)象是一個(gè)對(duì)方法的引用,但它并不包含方法所屬的對(duì)象實(shí)例。因此,在使用MethodHandle之前,需要通過bind方法將方法接收者(即調(diào)用方法的對(duì)象實(shí)例)綁定到MethodHandle上。
調(diào)用方法:一旦獲取到綁定了方法接收者的MethodHandle對(duì)象,就可以使用它來調(diào)用相應(yīng)的方法。MethodHandle提供了一系列invoke方法,用于根據(jù)方法的不同簽名進(jìn)行調(diào)用。
MethodHandles的工作原理是基于底層的字節(jié)碼指令,它直接操作方法、字段和構(gòu)造函數(shù)的字節(jié)碼,而不是通過反射API間接地調(diào)用它們。這使得MethodHandles比傳統(tǒng)的反射API更高效。
MethodHandles的性能優(yōu)勢(shì)主要體現(xiàn)在以下幾個(gè)方面:
內(nèi)聯(lián)優(yōu)化:MethodHandles在字節(jié)碼級(jí)別上進(jìn)行操作,可以進(jìn)行更好的內(nèi)聯(lián)優(yōu)化,減少方法調(diào)用的開銷。
類型檢查:MethodHandles在編譯時(shí)進(jìn)行類型檢查,而不是在運(yùn)行時(shí)。這使得類型錯(cuò)誤能夠在編譯時(shí)被發(fā)現(xiàn),而不是在運(yùn)行時(shí)拋出異常。
訪問權(quán)限檢查:MethodHandles可以直接訪問private方法、字段和構(gòu)造函數(shù),而不受訪問權(quán)限的限制。
適應(yīng)動(dòng)態(tài)語言:MethodHandles支持對(duì)動(dòng)態(tài)語言(如動(dòng)態(tài)類型語言)的調(diào)用,使得與傳統(tǒng)的反射API相比更加靈活。
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) throws Throwable {
MethodHandle handle = MethodHandles.lookup().findConstructor(Student.class, MethodType.methodType(void.class, int.class));
Student student = (Student) handle.invoke(10);
System.out.println(JSONUtil.toJsonPrettyStr(student));
}
}
{
"age": 10
}
Process finished with exit code 0
7 使用 Unfase
在 Java 中,Unsafe 是一個(gè)類提供了一些底層操作的方法,允許我們直接操縱內(nèi)存和執(zhí)行一些不安全的操作。Unsafe 類提供了訪問 Java 虛擬機(jī)底層操作的能力,包括直接操作內(nèi)存、執(zhí)行本地方法、加載類、分配實(shí)例等。
通過使用 Unsafe 類的方法之一,allocateInstance(Class cls),可以在不調(diào)用構(gòu)造函數(shù)的情況下創(chuàng)建對(duì)象。這是一種比較底層的操作,它會(huì)繞過類的構(gòu)造函數(shù),直接在內(nèi)存中分配對(duì)象的空間。
這個(gè)方法的實(shí)現(xiàn)原理如下:
首先,allocateInstance(Class cls) 方法會(huì)獲取傳入的類的類描述符(Class Descriptor),該描述符包含了類的結(jié)構(gòu)信息。
然后,Unsafe 類會(huì)根據(jù)類的描述符在堆中分配一塊內(nèi)存空間,這塊空間足夠存儲(chǔ)類的實(shí)例對(duì)象。
接下來,Unsafe 類會(huì)對(duì)這塊內(nèi)存空間進(jìn)行初始化,將其中的數(shù)據(jù)初始化為默認(rèn)值(對(duì)于基本類型,會(huì)初始化為 0 或者默認(rèn)值,對(duì)于引用類型,會(huì)初始化為 null)。
最后,allocateInstance(Class cls) 方法會(huì)返回這個(gè)內(nèi)存空間的引用作為結(jié)果,即創(chuàng)建了一個(gè)新的對(duì)象實(shí)例。文章來源:http://www.zghlxwxcb.cn/news/detail-462010.html
需要注意的是,使用 Unsafe 類創(chuàng)建對(duì)象是一種底層的操作,需要特別小心使用。因?yàn)樗鼤?huì)繞過構(gòu)造函數(shù),可能導(dǎo)致對(duì)象處于不一致的狀態(tài),或者執(zhí)行一些不安全的操作。這種方式一般用于某些特殊需求的場景,比如一些框架或庫的底層實(shí)現(xiàn)。對(duì)于普通的應(yīng)用開發(fā),一般不需要使用 Unsafe 類創(chuàng)建對(duì)象。文章來源地址http://www.zghlxwxcb.cn/news/detail-462010.html
package com.xu.es.document.entity;
import cn.hutool.json.JSONUtil;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
* @author x
* @date 2023/5/25 21:38
* @description: Java 創(chuàng)建對(duì)象的方式
* @title: Test
* @package com.xu.es.document.entity
*/
public class Test {
public static void main(String[] args) throws Throwable {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
Student student = (Student) unsafe.allocateInstance(Student.class);
System.out.println(JSONUtil.toJsonPrettyStr(student));
}
}
到了這里,關(guān)于Java 創(chuàng)建對(duì)象的7種方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!