Java 創(chuàng)建對(duì)象的幾種常見方式
在 Java 世界中,對(duì)象是面向?qū)ο缶幊痰暮诵?。無論是簡單的 Hello World 程序,還是復(fù)雜的企業(yè)級(jí)應(yīng)用,創(chuàng)建對(duì)象都是最基礎(chǔ)也最頻繁的操作。但你知道嗎?Java 中創(chuàng)建對(duì)象的方式遠(yuǎn)不止 new 關(guān)鍵字這一種。本文將帶你深入探索 Java 創(chuàng)建對(duì)象的 5 種常用方式,剖析它們的底層原理、適用場景及優(yōu)缺點(diǎn),幫助你在不同場景下做出最優(yōu)選擇。
一、使用new關(guān)鍵字:最直觀的創(chuàng)建方式
原理與用法
new 關(guān)鍵字是 Java 中創(chuàng)建對(duì)象最基本、最常用的方式。當(dāng)我們使用 new 時(shí),JVM 會(huì)完成以下步驟:
- 檢查類是否已加載,若未加載則觸發(fā)類加載流程;
- 為對(duì)象分配內(nèi)存空間(在堆中);
- 初始化對(duì)象的實(shí)例變量(默認(rèn)值或顯式初始化值);
- 調(diào)用類的構(gòu)造方法(無參或有參)完成對(duì)象初始化;
- 返回對(duì)象的引用(地址)給變量。
示例代碼:
// 定義一個(gè)簡單的類
class Person {
private String name;
private int age;
// 無參構(gòu)造方法
public Person() {}
// 有參構(gòu)造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter 略
}
// 使用 new 關(guān)鍵字創(chuàng)建對(duì)象
public class NewDemo {
public static void main(String[] args) {
Person p1 = new Person(); // 調(diào)用無參構(gòu)造
Person p2 = new Person("張三", 25); // 調(diào)用有參構(gòu)造
}
}適用場景
- 絕大多數(shù)日常開發(fā)場景,尤其是當(dāng)我們明確知道要?jiǎng)?chuàng)建的類類型,且需要直接控制對(duì)象初始化過程時(shí)。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):簡單直觀,易于理解和使用,性能開銷小。
- 缺點(diǎn):耦合度高(直接依賴具體類),不適合需要?jiǎng)討B(tài)創(chuàng)建對(duì)象的場景(如框架開發(fā))。
二、反射機(jī)制:動(dòng)態(tài)創(chuàng)建對(duì)象的 “利器”
反射是 Java 中一種強(qiáng)大的機(jī)制,它允許程序在運(yùn)行時(shí)獲取類的信息,并動(dòng)態(tài)調(diào)用類的方法、構(gòu)造方法等。通過反射創(chuàng)建對(duì)象,無需在編譯期確定具體類,極大地提升了程序的靈活性。
2.1Class.newInstance()方法
該方法通過類的 Class 對(duì)象調(diào)用,只能觸發(fā)類的無參構(gòu)造方法,且要求構(gòu)造方法必須是 public 的(否則會(huì)拋出 IllegalAccessException)。
示例代碼:
public class ReflectDemo1 {
public static void main(String[] args) {
try {
// 1. 獲取 Person 類的 Class 對(duì)象
Class<Person> personClass = Person.class;
// 2. 調(diào)用 newInstance() 創(chuàng)建對(duì)象(依賴無參構(gòu)造)
Person p = personClass.newInstance();
// 3. 后續(xù)操作
p.setName("李四");
System.out.println(p.getName()); // 輸出:李四
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}2.2Constructor.newInstance()方法
相比 Class.newInstance(),Constructor 類的 newInstance() 方法更靈活:
- 支持調(diào)用任意參數(shù)的構(gòu)造方法(包括有參構(gòu)造);
- 可以通過
setAccessible(true)訪問私有構(gòu)造方法(突破訪問權(quán)限限制)。
示例代碼:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo2 {
public static void main(String[] args) {
try {
// 1. 獲取 Class 對(duì)象
Class<Person> personClass = Person.class;
// 2. 獲取有參構(gòu)造方法(參數(shù)為 String 和 int)
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
// 3. 調(diào)用構(gòu)造方法創(chuàng)建對(duì)象
Person p = constructor.newInstance("王五", 30);
System.out.println(p.getName() + "," + p.getAge()); // 輸出:王五,30
// 4. 訪問私有構(gòu)造方法(假設(shè) Person 有一個(gè)私有構(gòu)造)
Constructor<Person> privateConstructor = personClass.getDeclaredConstructor(String.class);
privateConstructor.setAccessible(true); // 暴力訪問私有方法
Person p2 = privateConstructor.newInstance("趙六");
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}適用場景
- 框架開發(fā)(如 Spring、MyBatis):通過配置文件動(dòng)態(tài)創(chuàng)建對(duì)象,降低框架與具體類的耦合;
- 動(dòng)態(tài)代理、序列化等需要在運(yùn)行時(shí)處理未知類的場景。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):靈活性極高,可動(dòng)態(tài)創(chuàng)建對(duì)象,支持訪問私有構(gòu)造。
- 缺點(diǎn):性能開銷較大(反射操作需要解析類信息),代碼可讀性降低,過度使用會(huì)增加系統(tǒng)復(fù)雜度。
三、clone()方法:對(duì)象的 “復(fù)制粘貼”
clone() 方法用于創(chuàng)建一個(gè)現(xiàn)有對(duì)象的副本,它基于原對(duì)象的屬性值快速生成新對(duì)象,且不調(diào)用任何構(gòu)造方法。
實(shí)現(xiàn)條件
要使用 clone() 方法,類必須滿足兩個(gè)條件:
- 實(shí)現(xiàn)
Cloneable接口(標(biāo)記接口,無實(shí)際方法,僅用于標(biāo)識(shí)該類支持克?。?; - 重寫
Object類的clone()方法(默認(rèn)是protected權(quán)限,需改為public)。
示例代碼
// 實(shí)現(xiàn) Cloneable 接口
class Student implements Cloneable {
private String name;
private int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
// 重寫 clone() 方法
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
// getter/setter 略
}
public class CloneDemo {
public static void main(String[] args) {
try {
Student s1 = new Student("小明", 3);
Student s2 = s1.clone(); // 克隆對(duì)象
System.out.println(s1 == s2); // 輸出:false(不同對(duì)象)
System.out.println(s1.getName().equals(s2.getName())); // 輸出:true(屬性值相同)
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}淺拷貝與深拷貝
- 淺拷貝:
super.clone()默認(rèn)是淺拷貝,即對(duì)于引用類型屬性,僅復(fù)制引用地址(新對(duì)象與原對(duì)象共享該屬性的實(shí)際內(nèi)容)。 - 深拷貝:若需復(fù)制引用類型屬性的實(shí)際內(nèi)容,需在
clone()方法中手動(dòng)處理(如對(duì)引用對(duì)象再次調(diào)用clone())。
適用場景
- 需要快速復(fù)制對(duì)象,且原對(duì)象與副本對(duì)象的初始屬性一致時(shí)(如原型模式)。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):無需調(diào)用構(gòu)造方法,復(fù)制效率高,適合對(duì)象屬性較多的場景。
- 缺點(diǎn):僅能復(fù)制已有對(duì)象,無法創(chuàng)建全新對(duì)象;淺拷貝可能導(dǎo)致共享引用問題,深拷貝實(shí)現(xiàn)復(fù)雜。
四、序列化與反序列化:跨平臺(tái)的對(duì)象 “傳送門”
序列化是將對(duì)象轉(zhuǎn)換為字節(jié)流的過程,反序列化則是將字節(jié)流還原為對(duì)象的過程。通過反序列化創(chuàng)建對(duì)象時(shí),JVM 會(huì)重新生成一個(gè)獨(dú)立的對(duì)象,且不調(diào)用任何構(gòu)造方法。
實(shí)現(xiàn)條件
- 類必須實(shí)現(xiàn)
Serializable接口(標(biāo)記接口,標(biāo)識(shí)該類可序列化); - 若類中包含引用類型屬性,該屬性的類也需實(shí)現(xiàn)
Serializable(否則會(huì)拋出NotSerializableException)。
示例代碼
import java.io.*;
// 實(shí)現(xiàn) Serializable 接口
class Book implements Serializable {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
// getter/setter 略
}
public class SerializeDemo {
// 序列化:將對(duì)象寫入文件
public static void serialize(Book book, String filePath) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
oos.writeObject(book);
}
}
// 反序列化:從文件讀取對(duì)象(創(chuàng)建新對(duì)象)
public static Book deserialize(String filePath) throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {
return (Book) ois.readObject();
}
}
public static void main(String[] args) {
try {
Book book1 = new Book("Java編程思想", 108.0);
// 序列化
serialize(book1, "book.ser");
// 反序列化創(chuàng)建新對(duì)象
Book book2 = deserialize("book.ser");
System.out.println(book1 == book2); // 輸出:false(不同對(duì)象)
System.out.println(book2.getTitle()); // 輸出:Java編程思想
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}適用場景
- 對(duì)象的網(wǎng)絡(luò)傳輸(如 RPC 調(diào)用);
- 對(duì)象的持久化存儲(chǔ)(如保存到文件或數(shù)據(jù)庫)。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):可跨平臺(tái)、跨網(wǎng)絡(luò)傳輸對(duì)象,適合分布式系統(tǒng)。
- 缺點(diǎn):性能開銷大(序列化 / 反序列化過程復(fù)雜),僅適用于需要傳輸或持久化的場景。
五、工廠模式:對(duì)象創(chuàng)建的 “中間商”
工廠模式是一種設(shè)計(jì)模式,它通過一個(gè) “工廠類” 統(tǒng)一負(fù)責(zé)對(duì)象的創(chuàng)建,將對(duì)象的創(chuàng)建與使用分離。這種方式隱藏了對(duì)象創(chuàng)建的細(xì)節(jié),降低了代碼耦合度。
簡單工廠模式示例
// 產(chǎn)品接口
interface Shape {
void draw();
}
// 具體產(chǎn)品:圓形
class Circle implements Shape {
@Override
public void draw() {
System.out.println("繪制圓形");
}
}
// 具體產(chǎn)品:矩形
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("繪制矩形");
}
}
// 工廠類:負(fù)責(zé)創(chuàng)建對(duì)象
class ShapeFactory {
// 根據(jù)類型創(chuàng)建不同對(duì)象
public static Shape getShape(String type) {
if ("circle".equals(type)) {
return new Circle();
} else if ("rectangle".equals(type)) {
return new Rectangle();
}
return null;
}
}
// 使用工廠創(chuàng)建對(duì)象
public class FactoryDemo {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("circle");
circle.draw(); // 輸出:繪制圓形
Shape rectangle = ShapeFactory.getShape("rectangle");
rectangle.draw(); // 輸出:繪制矩形
}
}適用場景
- 類的實(shí)例化過程復(fù)雜,需要統(tǒng)一管理(如參數(shù)校驗(yàn)、資源初始化);
- 需要隱藏具體類的實(shí)現(xiàn)細(xì)節(jié)(如框架中的
BeanFactory); - 需根據(jù)不同條件創(chuàng)建不同類型的對(duì)象(如根據(jù)配置創(chuàng)建不同數(shù)據(jù)庫的連接對(duì)象)。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):解耦對(duì)象的創(chuàng)建與使用,便于擴(kuò)展(新增產(chǎn)品只需修改工廠類),提高代碼可維護(hù)性。
- 缺點(diǎn):簡單工廠模式中,工廠類可能會(huì)因產(chǎn)品過多而變得臃腫(可通過抽象工廠模式優(yōu)化)。
總結(jié):如何選擇合適的創(chuàng)建方式?
| 創(chuàng)建方式 | 核心原理 | 適用場景 | 性能 | 靈活性 |
|---|---|---|---|---|
new 關(guān)鍵字 | 直接調(diào)用構(gòu)造方法 | 大多數(shù)常規(guī)開發(fā),已知類類型 | 高 | 低 |
| 反射機(jī)制 | 動(dòng)態(tài)調(diào)用構(gòu)造方法 | 框架開發(fā)、動(dòng)態(tài)創(chuàng)建對(duì)象 | 中 | 高 |
clone() 方法 | 復(fù)制現(xiàn)有對(duì)象屬性 | 對(duì)象復(fù)制、原型模式 | 高 | 中 |
| 序列化與反序列化 | 字節(jié)流轉(zhuǎn)換 | 網(wǎng)絡(luò)傳輸、持久化 | 低 | 中 |
| 工廠模式 | 工廠類統(tǒng)一創(chuàng)建 | 復(fù)雜對(duì)象創(chuàng)建、解耦需求 | 中 | 高 |
- 日常開發(fā)優(yōu)先用
new關(guān)鍵字,簡單直接; - 框架或動(dòng)態(tài)場景用反射;
- 復(fù)制對(duì)象用
clone(); - 傳輸或持久化用序列化;
- 復(fù)雜對(duì)象創(chuàng)建或解耦用工廠模式。
掌握這些創(chuàng)建對(duì)象的方式,不僅能幫助你寫出更靈活、高效的代碼,還能讓你更深入理解 Java 的底層機(jī)制(如類加載、內(nèi)存分配等)。在實(shí)際開發(fā)中,需根據(jù)具體場景權(quán)衡選擇,才能寫出高質(zhì)量的 Java 程序。
到此這篇關(guān)于Java :創(chuàng)建對(duì)象的幾種方式的文章就介紹到這了,更多相關(guān)Java 創(chuàng)建對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一篇文章細(xì)數(shù)Java中List的10個(gè)坑
在Java中List是一個(gè)有序集合,允許存儲(chǔ)重復(fù)的元素,它是Java集合框架的一部分,提供了對(duì)集合進(jìn)行各種操作的接口,這篇文章主要介紹了Java中List10個(gè)坑的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-11-11
SpringBoot實(shí)現(xiàn)圖形驗(yàn)證碼的操作方法
隨著安全性的要求越來越高,目前許多項(xiàng)目中都使用了驗(yàn)證碼,驗(yàn)證碼也有各種類型,如 圖形驗(yàn)證碼、短信驗(yàn)證碼、郵件驗(yàn)證碼、人臉識(shí)別等,本文給大家介紹SpringBoot實(shí)現(xiàn)圖形驗(yàn)證碼的方法,感興趣的朋友跟隨小編一起看看吧2024-07-07
SpringBoot POST請(qǐng)求接收多個(gè)參數(shù)值為null問題
SpringBoot接口中POST請(qǐng)求接收J(rèn)SON數(shù)據(jù)時(shí),使用簡單類型接收會(huì)報(bào)null,需要封裝成實(shí)體類或使用Map(并注明泛型)接收,并且使用@RequestBody注解2025-02-02
java StringBuilder類的詳解及簡單實(shí)例
這篇文章主要介紹了java StringBuilder類的詳解及簡單實(shí)例的相關(guān)資料,實(shí)現(xiàn)了StringBuilder類的追加、插入、替換、刪除等操作,需要的朋友可以參考下2017-08-08

