Java 创建对象的几种常见方式

 更新时间:2025年09月16日 15:01:36   作者:码luffyliu  
本文将带你深入探索Java创建对象的5种常用方式,剖析它们的底层原理、适用场景及优缺点,帮助你在不同场景下做出最优选择,感兴趣的朋友跟随小编一起看看吧

在 Java 世界中,对象是面向对象编程的核心。无论是简单的 Hello World 程序,还是复杂的企业级应用,创建对象都是最基础也最频繁的操作。但你知道吗?Java 中创建对象的方式远不止 new 关键字这一种。本文将带你深入探索 Java 创建对象的 5 种常用方式,剖析它们的底层原理、适用场景及优缺点,帮助你在不同场景下做出最优选择。

一、使用new关键字:最直观的创建方式

原理与用法

new 关键字是 Java 中创建对象最基本、最常用的方式。当我们使用 new 时,JVM 会完成以下步骤:

  1. 检查类是否已加载,若未加载则触发类加载流程;
  2. 为对象分配内存空间(在堆中);
  3. 初始化对象的实例变量(默认值或显式初始化值);
  4. 调用类的构造方法(无参或有参)完成对象初始化;
  5. 返回对象的引用(地址)给变量。

示例代码

// 定义一个简单的类
class Person {
    private String name;
    private int age;
    // 无参构造方法
    public Person() {}
    // 有参构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // getter/setter 略
}
// 使用 new 关键字创建对象
public class NewDemo {
    public static void main(String[] args) {
        Person p1 = new Person(); // 调用无参构造
        Person p2 = new Person("张三", 25); // 调用有参构造
    }
}

适用场景

  • 绝大多数日常开发场景,尤其是当我们明确知道要创建的类类型,且需要直接控制对象初始化过程时。

优缺点

  • 优点:简单直观,易于理解和使用,性能开销小。
  • 缺点:耦合度高(直接依赖具体类),不适合需要动态创建对象的场景(如框架开发)。

二、反射机制:动态创建对象的 “利器”

反射是 Java 中一种强大的机制,它允许程序在运行时获取类的信息,并动态调用类的方法、构造方法等。通过反射创建对象,无需在编译期确定具体类,极大地提升了程序的灵活性。

2.1Class.newInstance()方法

该方法通过类的 Class 对象调用,只能触发类的无参构造方法,且要求构造方法必须是 public 的(否则会抛出 IllegalAccessException)。

示例代码

public class ReflectDemo1 {
    public static void main(String[] args) {
        try {
            // 1. 获取 Person 类的 Class 对象
            Class<Person> personClass = Person.class;
            // 2. 调用 newInstance() 创建对象(依赖无参构造)
            Person p = personClass.newInstance();
            // 3. 后续操作
            p.setName("李四");
            System.out.println(p.getName()); // 输出:李四
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

2.2Constructor.newInstance()方法

相比 Class.newInstance()Constructor 类的 newInstance() 方法更灵活:

  • 支持调用任意参数的构造方法(包括有参构造);
  • 可以通过 setAccessible(true) 访问私有构造方法(突破访问权限限制)。

示例代码

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo2 {
    public static void main(String[] args) {
        try {
            // 1. 获取 Class 对象
            Class<Person> personClass = Person.class;
            // 2. 获取有参构造方法(参数为 String 和 int)
            Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
            // 3. 调用构造方法创建对象
            Person p = constructor.newInstance("王五", 30);
            System.out.println(p.getName() + "," + p.getAge()); // 输出:王五,30
            // 4. 访问私有构造方法(假设 Person 有一个私有构造)
            Constructor<Person> privateConstructor = personClass.getDeclaredConstructor(String.class);
            privateConstructor.setAccessible(true); // 暴力访问私有方法
            Person p2 = privateConstructor.newInstance("赵六");
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

适用场景

  • 框架开发(如 Spring、MyBatis):通过配置文件动态创建对象,降低框架与具体类的耦合;
  • 动态代理、序列化等需要在运行时处理未知类的场景。

优缺点

  • 优点:灵活性极高,可动态创建对象,支持访问私有构造。
  • 缺点:性能开销较大(反射操作需要解析类信息),代码可读性降低,过度使用会增加系统复杂度。

三、clone()方法:对象的 “复制粘贴”

clone() 方法用于创建一个现有对象的副本,它基于原对象的属性值快速生成新对象,且不调用任何构造方法

实现条件

要使用 clone() 方法,类必须满足两个条件:

  1. 实现 Cloneable 接口(标记接口,无实际方法,仅用于标识该类支持克隆);
  2. 重写 Object 类的 clone() 方法(默认是 protected 权限,需改为 public)。

示例代码

// 实现 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(); // 克隆对象
            System.out.println(s1 == s2); // 输出:false(不同对象)
            System.out.println(s1.getName().equals(s2.getName())); // 输出:true(属性值相同)
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

浅拷贝与深拷贝

  • 浅拷贝super.clone() 默认是浅拷贝,即对于引用类型属性,仅复制引用地址(新对象与原对象共享该属性的实际内容)。
  • 深拷贝:若需复制引用类型属性的实际内容,需在 clone() 方法中手动处理(如对引用对象再次调用 clone())。

适用场景

  • 需要快速复制对象,且原对象与副本对象的初始属性一致时(如原型模式)。

优缺点

  • 优点:无需调用构造方法,复制效率高,适合对象属性较多的场景。
  • 缺点:仅能复制已有对象,无法创建全新对象;浅拷贝可能导致共享引用问题,深拷贝实现复杂。

四、序列化与反序列化:跨平台的对象 “传送门”

序列化是将对象转换为字节流的过程,反序列化则是将字节流还原为对象的过程。通过反序列化创建对象时,JVM 会重新生成一个独立的对象,且不调用任何构造方法

实现条件

  • 类必须实现 Serializable 接口(标记接口,标识该类可序列化);
  • 若类中包含引用类型属性,该属性的类也需实现 Serializable(否则会抛出 NotSerializableException)。

示例代码

import java.io.*;
// 实现 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 {
    // 序列化:将对象写入文件
    public static void serialize(Book book, String filePath) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
            oos.writeObject(book);
        }
    }
    // 反序列化:从文件读取对象(创建新对象)
    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");
            // 反序列化创建新对象
            Book book2 = deserialize("book.ser");
            System.out.println(book1 == book2); // 输出:false(不同对象)
            System.out.println(book2.getTitle()); // 输出:Java编程思想
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

适用场景

  • 对象的网络传输(如 RPC 调用);
  • 对象的持久化存储(如保存到文件或数据库)。

优缺点

  • 优点:可跨平台、跨网络传输对象,适合分布式系统。
  • 缺点:性能开销大(序列化 / 反序列化过程复杂),仅适用于需要传输或持久化的场景。

五、工厂模式:对象创建的 “中间商”

工厂模式是一种设计模式,它通过一个 “工厂类” 统一负责对象的创建,将对象的创建与使用分离。这种方式隐藏了对象创建的细节,降低了代码耦合度。

简单工厂模式示例

// 产品接口
interface Shape {
    void draw();
}
// 具体产品:圆形
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}
// 具体产品:矩形
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}
// 工厂类:负责创建对象
class ShapeFactory {
    // 根据类型创建不同对象
    public static Shape getShape(String type) {
        if ("circle".equals(type)) {
            return new Circle();
        } else if ("rectangle".equals(type)) {
            return new Rectangle();
        }
        return null;
    }
}
// 使用工厂创建对象
public class FactoryDemo {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.getShape("circle");
        circle.draw(); // 输出:绘制圆形
        Shape rectangle = ShapeFactory.getShape("rectangle");
        rectangle.draw(); // 输出:绘制矩形
    }
}

适用场景

  • 类的实例化过程复杂,需要统一管理(如参数校验、资源初始化);
  • 需要隐藏具体类的实现细节(如框架中的 BeanFactory);
  • 需根据不同条件创建不同类型的对象(如根据配置创建不同数据库的连接对象)。

优缺点

  • 优点:解耦对象的创建与使用,便于扩展(新增产品只需修改工厂类),提高代码可维护性。
  • 缺点:简单工厂模式中,工厂类可能会因产品过多而变得臃肿(可通过抽象工厂模式优化)。

总结:如何选择合适的创建方式?

创建方式核心原理适用场景性能灵活性
new 关键字直接调用构造方法大多数常规开发,已知类类型
反射机制动态调用构造方法框架开发、动态创建对象
clone() 方法复制现有对象属性对象复制、原型模式
序列化与反序列化字节流转换网络传输、持久化
工厂模式工厂类统一创建复杂对象创建、解耦需求
  • 日常开发优先用 new 关键字,简单直接;
  • 框架或动态场景用反射;
  • 复制对象用 clone()
  • 传输或持久化用序列化;
  • 复杂对象创建或解耦用工厂模式。

掌握这些创建对象的方式,不仅能帮助你写出更灵活、高效的代码,还能让你更深入理解 Java 的底层机制(如类加载、内存分配等)。在实际开发中,需根据具体场景权衡选择,才能写出高质量的 Java 程序。

到此这篇关于Java :创建对象的几种方式的文章就介绍到这了,更多相关Java 创建对象内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Intellj idea新建的java源文件夹不是蓝色的图文解决办法

    Intellj idea新建的java源文件夹不是蓝色的图文解决办法

    idea打开java项目后新建的模块中,java文件夹需要变成蓝色,这篇文章主要给大家介绍了关于Intellj idea新建的java源文件夹不是蓝色的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • Java中常用的设计模式之建造者模式详解

    Java中常用的设计模式之建造者模式详解

    这篇文章主要为大家详细介绍了Java中常用的设计模式之建造者模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • IDEA更改Terminal的方法步骤

    IDEA更改Terminal的方法步骤

    Windows上开发有时候cmd不支持bash命令,有些操作就会非常麻烦,本文主要介绍了IDEA更改Terminal的方法步骤,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Java虚拟机JVM栈溢出的问题解决

    Java虚拟机JVM栈溢出的问题解决

    Java虚拟机栈溢出是指在Java程序中,当线程调用的方法层级过深,导致栈空间溢出的情况,本文就详细的介绍了下产生的原因以及优化,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • SpringBoot DataSource数据源实现自动配置流程详解

    SpringBoot DataSource数据源实现自动配置流程详解

    这篇文章主要介绍了SpringBoot DataSource数据源实现自动配置流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-10-10
  • Java获取Linux服务器CPU、内存、磁盘信息的示例详解

    Java获取Linux服务器CPU、内存、磁盘信息的示例详解

    本文介绍了使用Java内置API、第三方库OSHI及JMX和命令行工具监控Linux服务器CPU、内存、磁盘等系统信息的方法,并提供示例代码实现整合监控功能,需要的朋友可以参考下
    2025-06-06
  • mac下idea启动web项目报错java.net.SocketException:socket closed问题

    mac下idea启动web项目报错java.net.SocketException:socket closed

    本文主要介绍了作者在项目启动时遇到的一个问题——无法打开调试端口,经过一系列排查和尝试,最终发现是由于权限问题导致的,作者还分享了如何修改文件权限的方法,并提醒大家不要随意kill掉占用端口的进程
    2024-12-12
  • MybatisPlus的IPage失效的问题解决方案

    MybatisPlus的IPage失效的问题解决方案

    这篇文章主要介绍了MybatisPlus的IPage失效的问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Netty分布式ByteBuf缓冲区分配器源码解析

    Netty分布式ByteBuf缓冲区分配器源码解析

    这篇文章主要为大家介绍了Netty分布式ByteBuf缓冲区分配器源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • java设计模式之简单工厂模式简述

    java设计模式之简单工厂模式简述

    这篇文章主要为大家详细介绍了java设计模式之简单工厂模式,简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例,感兴趣的小伙伴们可以参考一下
    2016-08-08

最新评论