news 2026/7/13 0:35:26

Java 大厂面试高频题:别再只会 new 了!Java 创建对象竟然有这么多种方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 大厂面试高频题:别再只会 new 了!Java 创建对象竟然有这么多种方式

在学习 Java 时,我们最先接触的对象创建方式通常是:

Personperson=newPerson();

因此,很多初学者会认为 Java 创建对象只能使用new

实际上,Java 中常见的对象创建方式不止一种。除了直接使用new,还可以通过反射、克隆、反序列化、工厂方法等方式获得对象。

本文将介绍 Java 中常见的 6 种对象创建方式:

1. 使用 new 关键字 2. 使用反射调用构造方法 3. 使用 Class.newInstance() 4. 使用 clone() 克隆对象 5. 使用反序列化创建对象 6. 使用工厂方法获得对象

在理解这些方式之前,需要先明确:对象、引用变量和类不是同一个概念。

一、什么是创建对象?

先定义一个简单的Person类:

classPerson{privateStringname;publicPerson(){System.out.println("Person 构造方法执行了");}publicPerson(Stringname){this.name=name;System.out.println("有参构造方法执行了");}publicvoidsayHello(){System.out.println("你好,我是"+name);}}

创建对象时通常写:

Personperson=newPerson();

这句代码可以拆成三部分:

Person:变量的类型 person:引用变量 new Person():创建 Person 对象

真正创建出来的对象是:

newPerson()

person只是一个引用变量,它保存了对这个对象的引用。

可以类比为:

Person 类:房屋设计图 Person 对象:根据设计图建出的房子 person 变量:房子的门牌号

接下来看看 Java 创建对象的不同方式。


二、方式一:使用 new 关键字

使用new是最常见、最直接的对象创建方式。

Personperson=newPerson();

也可以调用有参构造方法:

Personperson=newPerson("张三");

执行new Person("张三")时,Java 大致会完成以下操作:

1. 在堆内存中为 Person 对象分配空间; 2. 为成员变量设置默认值; 3. 执行成员变量的显式初始化; 4. 执行构造代码块; 5. 调用对应的构造方法; 6. 返回新对象的引用。

使用:

publicclassTest{publicstaticvoidmain(String[]args){Personperson=newPerson("张三");person.sayHello();}}

输出:

有参构造方法执行了 你好,我是张三

特点

语法简单; 可读性强; 会调用构造方法; 是日常开发中最常用的方式。

大多数情况下,创建普通业务对象都应该优先使用new


三、方式二:使用反射调用构造方法

反射允许程序在运行过程中动态获取类的信息,并创建对象。

推荐使用:

Constructor.newInstance()

示例:

importjava.lang.reflect.Constructor;publicclassTest{publicstaticvoidmain(String[]args)throwsException{Class<Person>clazz=Person.class;Constructor<Person>constructor=clazz.getDeclaredConstructor(String.class);Personperson=constructor.newInstance("李四");person.sayHello();}}

输出:

有参构造方法执行了 你好,我是李四

代码解释如下。

首先获取PersonClass对象:

Class<Person>clazz=Person.class;

然后获取参数为String的构造方法:

Constructor<Person>constructor=clazz.getDeclaredConstructor(String.class);

最后通过构造方法创建对象:

Personperson=constructor.newInstance("李四");

如果要调用无参构造方法,可以写:

Constructor<Person>constructor=Person.class.getDeclaredConstructor();Personperson=constructor.newInstance();

为什么需要反射创建对象?

因为有些场景在编写代码时,并不知道最终要创建哪个类。

例如,配置文件中写着:

com.example.service.UserService

程序运行时读取这个类名,再动态创建对象。

很多框架内部都大量使用了反射,例如:

Spring Spring Boot MyBatis Hibernate JUnit Jackson

Spring 扫描到一个带有@Service注解的类后,可以通过反射创建它的对象,并交给 IoC 容器管理。

特点

可以动态决定创建哪个类; 可以调用无参或有参构造方法; 适合框架和底层工具开发; 代码比 new 复杂; 反射调用通常比直接 new 慢。

在现代 Java 中,通过反射创建对象时,通常推荐使用Constructor.newInstance()


四、方式三:使用 Class.newInstance()

以前还可以通过Class对象的newInstance()方法创建对象:

Personperson=Person.class.newInstance();

或者:

Class<?>clazz=Class.forName("Person");Personperson=(Person)clazz.newInstance();

这段代码会调用Person的无参构造方法。

但是这种方式存在明显限制:

只能调用无参构造方法; 异常处理不够清晰; 无法灵活选择构造方法; 该方法已经被废弃。

因此,现在不建议继续使用:

clazz.newInstance();

推荐改成:

Personperson=Person.class.getDeclaredConstructor().newInstance();

也就是说,Class.newInstance()可以作为面试知识点了解,但新项目中应该使用Constructor.newInstance()


五、方式四:使用 clone() 克隆对象

clone()的作用不是从零开始创建一个全新状态的对象,而是根据已有对象复制出一个新对象。

首先让类实现Cloneable接口:

classPersonimplementsCloneable{privateStringname;publicPerson(Stringname){this.name=name;System.out.println("构造方法执行了");}publicStringgetName(){returnname;}@OverridepublicPersonclone()throwsCloneNotSupportedException{return(Person)super.clone();}}

使用:

publicclassTest{publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{Personp1=newPerson("王五");Personp2=p1.clone();System.out.println(p1==p2);System.out.println(p2.getName());}}

输出:

构造方法执行了 false 王五

注意,构造方法只执行了一次。

执行:

Personp2=p1.clone();

时,并不会再次调用Person的构造方法。

同时:

p1==p2

结果为false,说明p1p2指向两个不同的对象。

clone() 默认是浅拷贝

如果Person中包含一个引用类型成员:

classAddress{Stringcity;}classPersonimplementsCloneable{Stringname;Addressaddress;@OverridepublicPersonclone()throwsCloneNotSupportedException{return(Person)super.clone();}}

执行:

Personp2=p1.clone();

会得到:

p1 和 p2 是不同的 Person 对象; p1.address 和 p2.address 指向同一个 Address 对象。

也就是说,super.clone()默认实现的是浅拷贝。

如果需要深拷贝,还需要继续复制内部对象。

特点

根据已有对象复制新对象; 通常不会调用构造方法; 默认是浅拷贝; 需要实现 Cloneable; 适合复制已有对象状态。

六、方式五:使用反序列化创建对象

序列化是把对象转换成字节数据,反序列化则是把字节数据恢复成对象。

首先让类实现Serializable

importjava.io.Serializable;classPersonimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privateStringname;publicPerson(Stringname){this.name=name;System.out.println("构造方法执行了");}publicStringgetName(){returnname;}}

把对象序列化到文件:

importjava.io.FileOutputStream;importjava.io.ObjectOutputStream;Personperson=newPerson("赵六");try(ObjectOutputStreamoutput=newObjectOutputStream(newFileOutputStream("person.dat"))){output.writeObject(person);}

再通过反序列化恢复对象:

importjava.io.FileInputStream;importjava.io.ObjectInputStream;Personperson;try(ObjectInputStreaminput=newObjectInputStream(newFileInputStream("person.dat"))){person=(Person)input.readObject();}System.out.println(person.getName());

反序列化会根据文件中的数据重新创建一个Person对象。

对于普通实现了Serializable的类,反序列化时通常不会调用该可序列化类的构造方法。

使用场景

反序列化常见于:

读取持久化对象; 网络传输; 缓存恢复; 消息通信; 对象深拷贝。

不过,Java 原生序列化存在性能、安全性和兼容性方面的问题。现代项目中,更常见的是使用:

JSON Protocol Buffers Kryo Avro

等格式传输或保存数据。

特点

根据已有的字节数据恢复对象; 通常不会调用当前类的构造方法; 类需要实现 Serializable; 可能存在安全和版本兼容问题。

不要反序列化不可信来源的数据,否则可能带来安全风险。


七、方式六:使用工厂方法获得对象

工厂方法是实际开发中非常常见的一种对象获取方式。

例如:

classPerson{privateStringname;privatePerson(Stringname){this.name=name;}publicstaticPersoncreate(Stringname){returnnewPerson(name);}}

使用:

Personperson=Person.create("小明");

表面上没有直接使用new,而是通过:

Person.create()

获得对象。

不过需要注意,工厂方法内部可能仍然使用了new

returnnewPerson(name);

因此,从 JVM 底层角度看,最终可能还是由new创建对象;但从调用者角度看,对象是通过工厂方法获得的。

工厂方法有什么好处?

1. 方法名更清晰
Person.createAdmin();Person.createGuest();Person.fromDatabase(data);

比多个含义不清晰的构造方法更容易理解。

2. 可以返回缓存对象

例如:

Integera=Integer.valueOf(100);Integerb=Integer.valueOf(100);

Integer.valueOf()可能返回缓存中的已有对象,而不是每次都创建新对象。

3. 可以返回子类对象
Animalanimal=AnimalFactory.create("dog");

工厂内部可以根据参数返回:

newDog()

或者:

newCat()

调用者不需要关心具体实现类。

4. 可以统一控制创建过程

工厂方法可以加入:

参数校验; 缓存; 对象池; 权限检查; 日志记录; 依赖注入。

常见例子

Java 中有很多工厂方法:

Integer.valueOf(10);List.of("A","B");LocalDate.of(2026,7,12);Optional.of("Java");Executors.newFixedThreadPool(5);

特点

隐藏对象创建细节; 方法名可以表达业务含义; 可以返回缓存对象或子类对象; 有利于降低代码耦合; 内部不一定每次都创建新对象。

严格来说,“通过工厂方法获得对象”不一定意味着每次都创建了新对象,因为它可能返回已有对象。


八、使用 Unsafe 创建对象

Java 底层还存在一种特殊方式:通过Unsafe分配对象。

概念上可以写成:

Personperson=(Person)unsafe.allocateInstance(Person.class);

它可以直接为对象分配内存,但不会正常调用构造方法。

Unsafe属于底层内部 API,可能破坏 Java 的封装性和对象初始化规则,一般业务开发中不应该使用。

它更可能出现在:

JVM 底层工具; 高性能框架; 序列化框架; 代理框架; 特殊测试场景。

对于初学者,只需要知道这种方式存在即可,不建议实际使用。


九、这些方式是否都会调用构造方法?

不同创建方式对构造方法的调用情况不同。

创建方式是否调用构造方法常见用途
new普通对象创建
Constructor.newInstance()反射、框架
Class.newInstance()会调用无参构造旧式反射,不推荐
clone()通常不会复制已有对象
反序列化当前可序列化类通常不会恢复对象
工厂方法取决于内部实现封装创建逻辑
Unsafe.allocateInstance()不会底层框架

这是面试中经常考察的一个重点:

使用new和反射调用构造器会执行构造方法;使用clone()和普通反序列化恢复当前类对象时,通常不会调用该类构造方法。


十、创建对象和获得对象有什么区别?

严格来说,有些方式是“真正创建新对象”,有些方式只是“获得一个对象”。

例如:

Integernumber=Integer.valueOf(100);

valueOf()可能返回缓存中的已有对象,因此不保证一定创建新对象。

再例如 Spring:

UserServiceuserService=applicationContext.getBean(UserService.class);

这里是从 Spring 容器获取对象,对象可能早已创建完成,并不是此时才创建。

因此,下面两种说法存在细微区别:

创建对象:明确产生一个新的对象实例; 获得对象:拿到一个对象引用,可能是新对象,也可能是已有对象。

不过在初级面试题中,工厂方法、Spring 容器等方式经常也会被归入“对象创建方式”进行讨论。


十一、实际开发应该选择哪种方式?

普通业务对象

优先使用:

newPerson();

代码直观、简单。

框架动态创建对象

使用反射:

clazz.getDeclaredConstructor().newInstance();

复制已有对象

可以使用:

拷贝构造方法; clone(); 手动字段复制。

相比clone(),很多项目更喜欢使用拷贝构造方法,因为逻辑更加明确:

Personcopied=newPerson(original);

从文件、缓存或网络恢复对象

可以使用反序列化,但实际项目中通常优先考虑 JSON、Protobuf 等方案。

隐藏复杂创建逻辑

使用工厂方法:

Personperson=PersonFactory.create(type);

十二、常见面试问题

1. Java 创建对象有哪些方式?

可以回答:

Java 创建或获得对象的常见方式包括:使用 new 关键字、使用反射调用构造方法、通过 clone() 克隆对象、通过反序列化恢复对象,以及通过静态工厂方法或工厂模式获得对象。其中,Class.newInstance() 已经被废弃,反射创建对象推荐使用 Constructor.newInstance()。

2. 哪些方式不会调用构造方法?

可以回答:

使用 clone() 克隆对象通常不会调用构造方法,通过 Java 反序列化恢复当前可序列化类对象时通常也不会调用该类构造方法,Unsafe.allocateInstance() 同样不会调用构造方法。

3. newInstance() 推荐使用哪一个?

推荐:

clazz.getDeclaredConstructor().newInstance();

不推荐:

clazz.newInstance();

因为后者已经被废弃,并且只能调用无参构造方法。


十三、总结

Java 中常见的对象创建或获取方式包括:

1. new:最常用,会调用构造方法; 2. Constructor.newInstance():通过反射调用构造方法; 3. Class.newInstance():旧式反射方式,已经废弃; 4. clone():复制已有对象,通常不调用构造方法; 5. 反序列化:从字节数据恢复对象; 6. 工厂方法:隐藏创建细节,可能创建新对象,也可能返回已有对象; 7. Unsafe:底层特殊方式,不建议普通开发使用。

初学者最需要掌握的是:

new 反射 clone 反序列化 工厂方法

最后用一句话概括:

Java 创建对象不只有new,还可以通过反射、克隆、反序列化和工厂方法等方式获得对象;它们最大的区别在于创建过程是否调用构造方法、是否依赖已有对象,以及是否真正生成新的对象实例。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 0:12:57

团队协作中的技术栈选择:平衡效率与可维护性

技术栈选错的那一刻&#xff0c;团队就已经在负债很多团队在起步阶段会陷入一个幻觉&#xff1a;只要选一个“最流行”或者“最熟悉”的技术栈&#xff0c;就能同时赢得开发速度和长期稳健。但真实情况往往相反——效率的假象会在项目进入第6个月后全面崩塌。我曾经见过一个创业…

作者头像 李华
网站建设 2026/7/13 0:08:50

62-LangGraph有状态AI工作流-状态图-条件边-审批Agent实现

文章目录【62.PythonAI】LangGraph实战&#xff1a;用状态图构建有状态的AI工作流导入语1 ~> 为什么需要状态图1.1 LangChain Chain 的局限1.2 真实业务需要什么2 ~> LangGraph 核心概念2.1 四大要素2.2 State 的定义2.3 状态图构建五步法3 ~> 完整案例&#xff1a;文…

作者头像 李华
网站建设 2026/7/13 0:08:24

Windows系统文件blb_ps.dll丢失找不到问题解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/7/13 0:07:34

HarmonyKit | 鸿蒙开发:@kit.UIDesignKit 组件体系完整解读

HarmonyKit | 鸿蒙开发&#xff1a;kit.UIDesignKit 组件体系完整解读 引言&#xff1a;一套组件体系&#xff0c;而非一个组件库 kit.UIDesignKit 是 HarmonyOS 在 API 22 引入的核心 UI 套件。在 HarmonyKit 项目中&#xff0c;它被用于首页的 Tab 导航&#xff08;HdsTabs…

作者头像 李华
网站建设 2026/7/13 0:02:38

Palworld存档编辑完全掌握:从零开始实现游戏数据可视化修改

Palworld存档编辑完全掌握&#xff1a;从零开始实现游戏数据可视化修改 【免费下载链接】palworld-save-tools Tools for converting Palworld .sav files to JSON and back 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-save-tools 你是否曾经想要调整Palwor…

作者头像 李华
网站建设 2026/7/12 23:59:35

RapidOCR:突破性多引擎架构实现微秒级实时文字识别

RapidOCR&#xff1a;突破性多引擎架构实现微秒级实时文字识别 【免费下载链接】RapidOCR &#x1f4c4; Awesome OCR multiple programing languages toolkits based on ONNX Runtime, OpenVINO, MNN, PaddlePaddle, TensorRT and PyTorch. 项目地址: https://gitcode.com/G…

作者头像 李华