一、基础创建方式
1.1 new关键字(最常用)
// 标准对象实例化
Person person = new Person();
特点:
- 直接调用类的构造方法
- 需要明确的类定义
- 编译时类型检查
1.2 反射机制
// 使用Class.newInstance()
Class<?> clazz = Class.forName("com.example.Person");
Person person = (Person) clazz.newInstance();
// 使用Constructor.newInstance()
Constructor<Person> constructor = Person.class.getDeclaredConstructor();
Person person = constructor.newInstance();
对比:
方式 | 是否需要无参构造 | 能否调用私有构造 | 异常处理 |
---|---|---|---|
Class.newInstance() | ✅ 必须 | ❌ | 包裹在反射异常中 |
Constructor.newInstance() | 支持任意参数构造 | ✅ 通过setAccessible(true) | 直接抛出InvocationTargetException |
二、对象复用技术
2.1 克隆(Clone)
class Person implements Cloneable {
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅拷贝
}
}
// 深拷贝示例
class Address implements Cloneable {
String city;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class DeepPerson implements Cloneable {
Address address;
@Override
public Object clone() throws CloneNotSupportedException {
DeepPerson cloned = (DeepPerson) super.clone();
cloned.address = (Address) address.clone();
return cloned;
}
}
2.2 反序列化
// 序列化对象
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {
oos.writeObject(new Person("Alice", 30));
}
// 反序列化创建新对象
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {
Person restoredPerson = (Person) ois.readObject();
}
注意事项:
- 必须实现
Serializable
接口 - 显式定义
serialVersionUID
防止版本不一致问题 - 反序列化不会调用构造方法
三、设计模式应用
3.1 工厂方法模式
// 汽车工厂示例
interface Car {
void drive();
}
class Sedan implements Car {
public void drive() {
System.out.println("驾驶轿车"); }
}
class SUV implements Car {
public void drive() {
System.out.println("驾驶SUV"); }
}
class CarFactory {
public static Car createCar(String type) {
switch(type) {
case "sedan": return new Sedan();
case "suv" : return new SUV();
default : throw new IllegalArgumentException();
}
}
}
// 使用示例
Car myCar = CarFactory.createCar("suv");
3.2 建造者模式
// 复杂对象创建
class Computer {
private String cpu;
private String ram;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
}
public static class Builder {
private String cpu;
private String ram;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder ram(String ram) {
this.ram = ram;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
// 使用示例
Computer pc = new Computer.Builder()
.cpu("i7")
.ram("32GB")
.build();
四、高级创建技术
4.1 静态工厂方法
// JDK中的经典实现
public final class LocalDateTime {
public static LocalDateTime now() {
// 实际实现逻辑
}
public static LocalDateTime of(int year, int month, int day, int hour, int minute) {
// 参数校验和构造逻辑
}
}
// 使用示例
LocalDateTime meetingTime = LocalDateTime.of(2023, 12, 25, 14, 30);
4.2 Lambda表达式创建
// 函数式接口实例化
Runnable task = () -> System.out.println("执行任务");
Comparator<String> lengthComparator = (s1, s2) -> s1.length() - s2.length();
// 等效匿名内部类
Runnable oldTask = new Runnable() {
@Override
public void run() {
System.out.println("传统实现方式");
}
};
五、框架级对象创建
5.1 Spring IOC容器
<!-- XML配置方式 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
</bean>
// 注解配置方式
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource(config);
}
}
六、创建方式对比
创建方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
new关键字 | 简单对象直接创建 | 直观高效 | 耦合度高 |
反射机制 | 动态加载类/框架开发 | 灵活性强 | 性能开销大 |
工厂方法 | 多态对象创建 | 解耦创建逻辑 | 增加类复杂度 |
建造者模式 | 复杂参数对象 | 参数灵活可读性好 | 代码量较大 |
克隆 | 对象复制场景 | 快速复制 | 深拷贝实现复杂 |
依赖注入 | 企业级应用 | 集中管理依赖关系 | 需要框架支持 |
七、注意事项
反射创建:
- 需要处理
InstantiationException
- 可能绕过访问权限检查(使用
setAccessible(true)
) - 性能比直接new低约50倍(需缓存Constructor)
- 需要处理
克隆陷阱:
Object.clone()
执行浅拷贝- 数组元素是引用类型时需特别注意
- 替代方案:使用复制构造器或序列化实现深拷贝
反序列化安全:
- 避免反序列化不可信来源的数据
- 使用
readObject()
方法进行输入验证 - 考虑使用
ObjectInputFilter
框架使用原则:
- Spring Bean默认单例模式
- 合理选择Bean作用域(prototype/request/session)
- 避免循环依赖
八、扩展知识接口
动态代理对象创建
interface Subject {
void request();
}
class RealSubject implements Subject {
public void request() {
System.out.println("真实请求");
}
}
class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
}
// 创建代理对象
Subject proxyInstance = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class[]{
Subject.class},
new DynamicProxyHandler(new RealSubject())
);
Unsafe类绕过构造方法
// 危险操作示例(仅作了解,实际不推荐使用)
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Person person = (Person) unsafe.allocateInstance(Person.class);
注意:
- 完全跳过构造方法执行
- 可能导致对象状态不一致
- 需要Java内部权限
- 实际开发中禁止使用
九、最佳实践建议
- 优先选择最简单的方式:能用new直接创建时不要过度设计
- 复杂对象使用建造者模式提高可读性
- 框架开发多用工厂方法实现扩展性
- 需要对象复用时考虑原型模式
- 企业级应用统一使用依赖注入
- 动态场景合理运用反射机制但要控制使用范围
根据具体业务需求选择合适的对象创建方式,在灵活性与性能之间找到最佳平衡点。对于核心高频创建的对象,建议进行性能压测。