Java 创建对象,除了 new 你还知道哪些方式?

昨晚加班的时候,同事来旁边坐着跟我闲聊,不经意间看到屏幕上的new 对象代码,他说:"每次这样new 一个对象感觉好丑,有没有更好的方式方法!"。

我说:"有啊,不过也得看场景,简单的直接用 new 一把梭哈!复杂的再考虑其它的方式"

那有哪些方式呢?下面来分享一下。

1. new关键字

最直接的创建方式

java 复制代码
// 就像我们平时说话:"来一辆新车"
Car car = new Car();

// 或者带参数的:"来一辆红色的宝马"
Car bmw = new Car("宝马", "红色");

使用场景 :这是最常用的方式,适合90%的日常开发场景。

优点

  • 简单直观,一眼就能看懂
  • 性能好,直接调用构造方法

缺点

  • 不够灵活,创建逻辑与使用代码耦合

2. 反射机制

有时候我们需要在运行时才知道要创建什么类的对象,这时候反射就派上用场了。

java 复制代码
// 传统方式:我知道要创建Car
Car car = new Car();

// 反射方式:运行时才知道要创建什么
try {
    Class carClass = Class.forName("com.example.Car");
    Constructor constructor = carClass.getConstructor();
    Car car = (Car) constructor.newInstance();
} catch (Exception e) {
    e.printStackTrace();
}

案例 :Spring框架中,当我们配置了@Component注解的类,Spring就是通过反射来创建这些对象的。

java 复制代码
// Spring内部大致是这样做的
Class beanClass = loadClass("com.example.UserService");
Object bean = beanClass.getDeclaredConstructor().newInstance();

3. clone()方法

假设你有一个配置好的对象,现在需要另一个一模一样的,这时候clone就很有用。

java 复制代码
class UserSettings implements Cloneable {
    private String theme = "dark";
    private int fontSize = 14;
    
    @Override
    public UserSettings clone() {
        try {
            return (UserSettings) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

// 使用clone
UserSettings original = new UserSettings();
UserSettings cloned = original.clone(); // 得到一个完全相同的副本

注意点

  • 需要实现Cloneable接口,否则会抛出异常
  • 默认是浅拷贝,如果需要深拷贝要自己实现

4. 反序列化

当我们把对象保存到文件或通过网络传输后,需要重新把它变回对象。

java 复制代码
// 对象需要实现Serializable接口
class GameSave implements Serializable {
    private static final long serialVersionUID = 1L;
    private int level;
    private int score;
}

// 保存对象到文件
try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("save.dat"))) {
    oos.writeObject(gameSave);
}

// 从文件读取对象
try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("save.dat"))) {
    GameSave loadedSave = (GameSave) ois.readObject();
    // loadedSave就是原来那个gameSave的副本
}


5. 静态工厂方法

有时候直接new不够表达我们的意图,这时候工厂方法就很有用。

java 复制代码
class Color {
    private int red, green, blue;
    
    private Color(int r, int g, int b) {
        this.red = r;
        this.green = g;
        this.blue = b;
    }
    
    // 静态工厂方法:语义更明确
    public static Color fromRGB(int r, int g, int b) {
        return new Color(r, g, b);
    }
    
    public static Color fromHex(String hex) {
        // 解析十六进制颜色码
        return new Color(/* 解析逻辑 */);
    }
    
    public static Color red() {
        return new Color(255, 0, 0);
    }
}

// 使用:这样读起来更自然
Color red = Color.red();
Color custom = Color.fromRGB(255, 128, 0);

优点

  • 方法名可以表达创建意图
  • 可以缓存对象,避免重复创建
  • 可以返回子类对象,更灵活

6. Builder模式

当对象有很多属性时,构造方法会变得很长很难读,Builder模式来解决!

java 复制代码
class Computer {
    private final String cpu;          // 必须
    private final String ram;          // 必须  
    private final String storage;      // 必须
    private final String graphicsCard; // 可选
    private final String monitor;      // 可选
    
    // 私有构造方法,只能通过Builder创建
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.graphicsCard = builder.graphicsCard;
        this.monitor = builder.monitor;
    }
    
    public static class Builder {
        // 必须参数
        private final String cpu;
        private final String ram;
        private final String storage;
        
        // 可选参数
        private String graphicsCard = "集成显卡";
        private String monitor = "23寸显示器";
        
        // Builder构造方法包含必须参数
        public Builder(String cpu, String ram, String storage) {
            this.cpu = cpu;
            this.ram = ram;
            this.storage = storage;
        }
        
        // 设置可选参数的方法
        public Builder graphicsCard(String graphicsCard) {
            this.graphicsCard = graphicsCard;
            return this;
        }
        
        public Builder monitor(String monitor) {
            this.monitor = monitor;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
}

// 使用Builder模式:链式调用,非常清晰
Computer gamingPC = new Computer.Builder("i7", "16GB", "1TB SSD")
    .graphicsCard("RTX 3080")
    .monitor("27寸4K显示器")
    .build();

适用场景

  • 对象有很多属性,特别是可选属性很多时
  • 希望创建过程更清晰、易读
  • 需要创建不可变对象

7. 匿名内部类

当我们只需要某个接口的一次性实现时,匿名内部类很方便。

java 复制代码
// 创建线程的传统方式
class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("执行任务");
    }
}

Runnable task1 = new MyTask();

// 使用匿名内部类:更简洁
Runnable task2 = new Runnable() {
    @Override
    public void run() {
        System.out.println("执行任务");
    }
};

// Java 8以后,可以用lambda表达式进一步简化
Runnable task3 = () -> System.out.println("执行任务");

8. 方法引用

Java 8引入了函数式编程,让对象创建更加优雅。

java 复制代码
class Person {
    private String name;
    
    public Person() {
        this.name = "匿名";
    }
    
    public Person(String name) {
        this.name = name;
    }
}

// 方法引用创建对象
Supplier defaultPerson = Person::new;
Function namedPerson = Person::new;

// 使用
Person p1 = defaultPerson.get();      // 调用无参构造
Person p2 = namedPerson.apply("张三"); // 调用有参构造

总结

场景 推荐方式 理由
日常开发 new关键字 简单直接,性能好
多参数对象 Builder模式 可读性好,灵活
需要封装创建逻辑 静态工厂方法 隐藏实现细节
框架开发 反射机制 动态性,灵活性
函数式编程 方法引用 代码简洁,表达力强
创建对象副本 clone()方法 语义明确,使用方便

简单场景用new,复杂对象用Builder,需要灵活性用工厂方法或反射。

本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《前端高手才知道的秘密:Blob 居然这么强大》

《这 5 个冷门 HTML 标签,让我直接删了100 行 JS 代码》

《重构了20个SpringBoot项目后,总结出这套稳定高效的架构设计》

《代码里全是 new 对象,真的很 Low 吗?我认真想了一晚》

相关推荐
shang_xs8 小时前
Java 25 ScopedValue - 作用域内安全访问的一种实现
java·开发语言·安全
小途软件8 小时前
基于深度学习的驾驶人情绪识别
java·人工智能·pytorch·python·深度学习·语言模型
明天有专业课8 小时前
简简单单设计模式-策略
后端
小白学大数据8 小时前
Java 异步爬虫高效获取小红书短视频内容
java·开发语言·爬虫·python·音视频
我命由我123458 小时前
Android Jetpack Compose - Compose 重组、AlertDialog、LazyColumn、Column 与 Row
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
愤怒的代码9 小时前
在 Android 中执行 View.invalidate() 方法后经历了什么
android·java·kotlin
memgLIFE9 小时前
SQL 优化方法详解(1)
java·数据库·sql
2201_757830879 小时前
Bean原理篇
java·开发语言
林太白9 小时前
ofd文件
前端·后端
小宇的天下9 小时前
Calibre 3Dstack--每日一个命令day 6 [process和export layout](3-6)
java·前端·数据库