1、简述
在 Java 开发中,“对象”是一切面向对象编程的基础。Java 提供了多种方式来创建对象,不同方式背后有不同的应用场景与运行机制。理解这些方法,对于提升系统性能、掌握底层机制都有重要价值。
2、创建对象
2.1 使用 new
关键字(最常见)
示例代码:
public class User {
String name;
}
User user = new User();
说明:
🔹 最常见、最直观的方式。
🔹 会调用构造方法,分配内存并初始化对象。
🔹 编译期类型安全,适用于绝大多数场景。
2.2 使用反射 Class.newInstance()
(不推荐)
示例代码:
Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();
注意事项:
🔹 要求类必须有无参构造方法。
🔹 在 Java 9 后被标记为过时(deprecated),建议使用 getDeclaredConstructor().newInstance()
替代。
🔹 会抛出 InstantiationException
、IllegalAccessException
。
2.3 使用反射 Constructor.newInstance()
(推荐反射方式)
示例代码:
Constructor<User> constructor = User.class.getDeclaredConstructor();
constructor.setAccessible(true);
User user = constructor.newInstance();
特点:
🔹 支持调用私有构造方法。
🔹 更灵活、安全(可以指定构造函数参数)。
🔹 常用于依赖注入、框架内部如 Spring、MyBatis。
2.4 使用 clone()
方法(浅拷贝)
示例代码:
public class User implements Cloneable {
String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 使用
User user1 = new User();
user1.name = "Tom";
User user2 = (User) user1.clone();
特点:
🔹 克隆一个已存在的对象,属于对象复制而非创建全新结构。
🔹 默认是浅拷贝,若包含引用类型字段需手动实现深拷贝。
🔹 需要实现 Cloneable
接口,否则抛出 CloneNotSupportedException
。
2.5 使用反序列化(从字节流创建)
示例代码:
// 序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
out.writeObject(user);
// 反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User user2 = (User) in.readObject();
特点:
🔹 常用于网络传输、缓存存储等场景。
🔹 类必须实现 Serializable
接口。
🔹 会跳过构造方法的调用(绕过 init 阶段)。
2.6 使用对象工厂(工厂模式)
示例代码:
public class UserFactory {
public static User createUser(String name) {
User user = new User();
user.name = name;
return user;
}
}
特点:
🔹 封装对象创建逻辑,便于集中管理。
🔹 工厂模式是实际开发中常用设计模式之一。
🔹 Spring 中的 BeanFactory / ApplicationContext 就是这种思想。
2.7 使用第三方库:如 CGLIB、Objenesis
CGLIB 动态代理创建对象(无构造函数调用)
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallback(new NoOp() {});
User proxyUser = (User) enhancer.create();
Objenesis
Objenesis objenesis = new ObjenesisStd();
User user = objenesis.newInstance(User.class);
特点:
🔹 用于创建不调用构造函数的对象(绕过 new、反射等限制)。
🔹 Spring、Mockito、Hibernate 等底层使用场景广泛。
🔹 不适合日常业务开发,更多用于框架底层实现。
2.8 总结对比
方式 | 是否调用构造函数 | 是否常用 | 应用场景 |
---|---|---|---|
new |
✅ 是 | ✅ 常用 | 普通对象创建 |
Class.newInstance() |
✅ 是 | ❌ 已过时 | 框架反射,旧代码中偶见 |
Constructor.newInstance() |
✅ 是 | ✅ 推荐 | Spring、框架依赖注入 |
clone() |
❌ 否(复制) | ⚠️ 慎用 | 对象拷贝、实现原型模式 |
反序列化 | ❌ 否 | ⚠️ 慎用 | 网络传输、缓存恢复 |
工厂方法 | ✅ 是 | ✅ 常用 | 面向接口编程、统一对象创建入口 |
Objenesis / CGLIB | ❌ 否 | ❌ 框架级 | Spring、Mock 框架底层、ORM 动态代理 |
实践建议
🔹 日常开发:首选 new
或工厂方法,代码清晰,易维护。
🔹 框架开发:选择反射 Constructor.newInstance()
或 Objenesis。
🔹 对象复制:优先考虑手动复制或使用库如 Apache Commons Lang
的 SerializationUtils
,避免使用 clone()
。
🔹 性能敏感:避免使用反序列化方式,风险高、开销大。
3、结语
Java 提供了多种方式创建对象,不同方式各有适用场景。掌握它们不仅有助于写出更灵活的代码,也有助于深入理解如 Spring、MyBatis、Dubbo 等优秀框架的实现原理。推荐大家多动手实践,如自己实现一个对象工厂,或基于反射构建简单容器,进一步巩固理解。
如果你想,我可以继续提供以下内容:
🔹 ✏️ 示例源码项目结构(含反射、clone、Objenesis等示例)
🔹 🧪 对比几种方式的创建性能(Benchmark)
🔹 📦 与 Spring Bean 创建过程的对应关系
是否需要我继续展开?