本文推荐阅读时间30分钟

大家都知道,在编写Java程序里,一般就是处理各种各样的对象,那么,你知道一共有多少种创建对象的方式吗?

希望大家能稍微思考一下再往下翻。

答案是4种

  • new 一个对象
  • 反射一个类实例化一个对象(反射类和反射构造方法)
  • clone 一个对象
  • 反序列化一个对象

前两者调用了构造方法,后两者没有调用。

其中,日常使用中,最为常见的是使用new关键字创建对象;而在框架之中,最常用的是反射来控制对象生成。

下面详细地梳理常见的new对象的逻辑

  1. 若编写一个新的类,此时没有任何额外的需求时,采用最简单的构造方法即可。
  2. 若对象属性很多,但其中必传属性不多,可以使用set设置属性,或者重叠构造器模式。
  3. 若对象的属性和方法的传参类似,可以使用org.springframework.beans.BeanUtils.copyProperties()方法搭配set方法来设置参数。
  4. 若对象需要有一些特殊功能,比如单例,能够缓存等,可以使用静态工厂方法。
  5. 若对象需要一次性构建(创建不可变对象),使用建造者模式。
  6. 若对象为底层资源,会被各种方法依赖,使用依赖注入。

1.1 Java原生构造方法,和类同名即可

public class Order {
private String code;
private List<String> offers;
private Map<String, Object> features;
public Order() {
}
public Order(String code, List<String> offers, Map<String, Object> features) {
this.code = code;
this.offers = offers;
this.features = features;
}
}

2.1 重叠构造器模式

public class Order {
// not null!
private String code;
private List<String> offers;
private Map<String, Object> features;
//传入code, offers设为空集合, features设为空表
public Order(String code) {
this(code, new ArrayList<>(), new HashMap<>());
}
//传入code, offers, features设为空表
public Order(String code, List<String> offers) {
this(code, offers, new HashMap<>());
}
//传入code,features,offers设为空集合
public Order(String code, Map<String, Object> features) {
this(code, new ArrayList<>(), features);
}
//传入code, offers, features
public Order(String code, List<String> offers, Map<String, Object> features) {
this.code = code;
this.offers = offers;
this.features = features;
}
}

2.2 set设置属性

public class Order {
private String code;
private List<String> offers;
private Map<String, Object> features; public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public List<String> getOffers() {
return offers;
}
public void setOffers(List<String> offers) {
this.offers = offers;
}
public Map<String, Object> getFeatures() {
return features;
}
public void setFeatures(Map<String, Object> features) {
this.features = features;
}
}

3.1 从传参中获取属性, 使用 org.springframework.beans.BeanUtils

//为省略代码量,使用lombok的@Data

//Order.java
@Data
public class Order {
private String code;
private List<String> offers;
private Map<String, Object> features;
} //FooModel.java
//和Order.java的属性一致
@Data
public class FooModel {
private String code;
private List<String> offers;
private Map<String, Object> features;
} //FooTest.class import org.springframework.beans.BeanUtils; public class FooTest {
public void handleFoo(FooModel model) {
Order order = new Order();
BeanUtils.copyProperties(model, order);
//处理order对象
}
}

4.1 静态工厂方法单例对象

/**
* 枚举来创建单例对象有以下优势
* 1.构造方法已私有化
* 2.是否多线程安全
* 3.支持序列化机制,防止多次序列化创建对象
*/
public enum Singleton {
INSTANCE;
public void method() {
//函数处理
}
}

4.2 静态工厂方法缓存对象

/**
* 下面以经典的Boolean.java来举例
* Boolean类创建了两个常量属性,TRUE和FALSE
* 在调用valueOf时使用这个缓存
*/
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{
//缓存 真
public static final Boolean TRUE = new Boolean(true);
//缓存 假
public static final Boolean FALSE = new Boolean(false); private final boolean value; public Boolean(boolean value) {
this.value = value;
} //返回缓存值,不新创建对象
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
}

5.1 Java8之前建造者模式(不依赖第三方库)

public class Order {
private String code;
private List<String> offers;
private Map<String, Object> features; public static Builder builder() {
return new Builder();
}
//私有化构造方法,只提供给Builder.build()使用
private Order(String code, List<String> offers, Map<String, Object> features) {
this.code = code;
this.offers = offers;
this.features = features;
} public String toString() {
return "Order(code=" + this.code + ", offers=" + this.offers + ", features=" + this.features + ")";
} public static class Builder {
private String code;
private List<String> offers;
private Map<String, Object> features; public Builder code(String code) {
this.code = code;
return this;
}
public Builder offers(List<String> offers) {
this.offers = offers;
return this;
}
public Builder offer(String offer) {
if (null == this.offers) {
this.offers = new ArrayList<>();
}
this.offers.add(offer);
return this;
}
public Builder features(Map<String, Object> features) {
this.features = features;
return this;
}
public Builder feature(String key, Object value) {
if (null == this.features) {
this.features = new HashMap<>();
}
this.features.put(key, value);
return this;
}
public Order build() {
return new Order(this.code, this.offers, this.features);
}
} public static void main(String[] args) {
Order order = Order.builder()
.code("1234")
.offer("满100减5")
.offer("满200减15")
.feature("color", "white")
.feature("category", "shirt")
.build();
System.out.println(order);
}
} /** 输出
Order(code=1234, offers=[满100减5, 满200减15], features={color=white, category=shirt}) Process finished with exit code 0
*/

5.2 Java8建造者模式(不依赖第三方库)

函数式接口和泛型构造器

@FunctionalInterface
public interface KeyValueConsumer<T, K, V> { void accept(T t, K k, V v); default KeyValueConsumer<T, K, V> andThen(KeyValueConsumer<? super T, ? super K, ? super V> after) {
Objects.requireNonNull(after);
return (t, k, v) -> {
accept(t, k, v);
after.accept(t, k, v);
};
}
} public class GenericBuilder<T> {
private final Supplier<T> instantiator;
private List<Consumer<T>> instantiatorModifiers = new ArrayList<>();
private List<Consumer<T>> keyValueModifiers = new ArrayList<>();
public GenericBuilder(Supplier<T> instantiator) {
this.instantiator = instantiator;
}
public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
return new GenericBuilder<T>(instantiator);
}
public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
Consumer<T> c = instance -> consumer.accept(instance, value);
instantiatorModifiers.add(c);
return this;
}
public <K, V> GenericBuilder<T> with(KeyValueConsumer<T, K, V> consumer, K key, V value) {
Consumer<T> c = instance -> consumer.accept(instance, key, value);
keyValueModifiers.add(c);
return this;
}
public T build() {
T value = instantiator.get();
instantiatorModifiers.forEach(modifier -> modifier.accept(value));
keyValueModifiers.forEach(keyValueModifier -> keyValueModifier.accept(value));
instantiatorModifiers.clear();
keyValueModifiers.clear();
return value;
}
}

实际操作类

package com.example.demo.bean;

import lombok.Builder;
import lombok.Singular;
import lombok.ToString; import java.util.*; public class Order {
private String code;
private List<String> offers;
private Map<String, Object> features; //省略无参构造方法,set、get,toString方法 public void addOffer(String offer) {
offers = Optional.ofNullable(offers)
.orElseGet(ArrayList::new);
offers.add(offer);
} public <T> void addFeature(String key, T value) {
features = Optional.ofNullable(features)
.orElseGet(HashMap::new);
features.put(key, value);
} public static void main(String[] args) {
Order order = GenericBuilder.of(Order::new)
.with(Order::setCode, "1234")
.with(Order::addOffer, "满200减15")
.with(Order::addOffer, "满200减15")
.with(Order::addFeature, "color", "white")
.with(Order::addFeature, "category", "shirt").build();
System.out.println(order);
}
} /** 输出
Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt}) Process finished with exit code 0
*/

5.3 lombok第三方库的建造者模式

@ToString
@Builder
public class Order {
private String code;
@Singular
private List<String> offers;
@Singular
private Map<String, Object> features; public static void main(String[] args) {
Order order = Order.builder()
.code("1234")
.offer("满100减5")
.offer("满200减15")
.feature("color", "white")
.feature("category", "shirt")
.build();
System.out.println(order);
}
} /** 输出
Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt}) Process finished with exit code 0
*/

6.1 依赖注入

这里移除了Spring的配置文件,只展示实际代码

@RestController
public class DemoController {
//自动注入demo的服务
@Autowired
private DemoService demoService; @GetMapping
public String getDemo() {
return demoService.get();
}

建造者模式来源于 如何实现Builder模式

单例模式来源于 Effective Java

Java随谈(三)如何创建好一个对象?的更多相关文章

  1. 【Java 线程的深入研究1】Java 提供了三种创建线程的方法

    Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...

  2. Java 数组的三种创建方法,数组拷贝方法

    public static void main(String[] args) {//创建数组的第一种方法int[] arr=new int[6];int intValue=arr[5];//Syste ...

  3. Java 数组的三种创建方法

    public static void main(String[] args) { //创建数组的第一种方法 int[] arr=new int[6]; int intValue=arr[5]; //S ...

  4. 《java多线程——线程简介与其创建(1)》

    Java 给多线程编程提供了内置的支持. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开 ...

  5. Java多线程(三)如何创建线程

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  6. “全栈2019”Java多线程第三章:创建多线程之实现Runnable接口

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. Java 网络编程(三) 创建和使用URL访问网络上的资源

    链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951877.html 创建和使用URL访问网络上的资源 URL(Uniform Reso ...

  8. 在Java中谈尾递归--尾递归和垃圾回收的比较(转载)

    我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...

  9. java学习(三)

    学号 20189214 <Java程序设计>第三周学习总结 教材学习内容总结 核心类 java.lang.Object 所有的类都直接派生自这个类. java.lang.String St ...

随机推荐

  1. 第一篇 Scrum冲刺博客

    一.Alpha任务认领 冯荣新 任务 预计时间 搜索框 0.5h 首页轮播图 0.5h 分类导航 2h 商品列表 2h 商品详情轮播图 0.5h 商品底部工具栏 1h 购物车列表 1.5h 购物车工具 ...

  2. Kafka内部实现原理

    Kafka是什么 在流式计算中,Kafka一般用来缓存数据,Storm通过消费Kafka的数据进行计算. 1)Apache Kafka是一个开源消息系统,由Scala写成.是由Apache软件基金会开 ...

  3. 区块链入门到实战(35)之Solidity – 变量作用域

    局部变量的作用域仅限于定义它们的函数,但是状态变量可以有三种作用域类型. Public – 公共状态变量可以在内部访问,也可以通过消息访问.对于公共状态变量,将生成一个自动getter函数. Inte ...

  4. 修改docker0网桥的IP段

    关闭docker进程 systemctl stop docker 修改/etc/docker/daemon.json { "bip": "100.96.2.1/24&qu ...

  5. Lombok插件有望被Intellij IDEA收编以改善兼容性问题

    1. 前言 最近两个版本的Intellij IDEA没有办法使用lombok插件了,这种问题已经出现了多次,导致胖哥依然使用2020.1的旧版本.其实很多人和我一样也回滚到了旧版本.我一直认为是lom ...

  6. 利用OpenCV进行H264视频编码的简易方式

    在Python下,利用pip安装预编译的opencv库,并实现h264格式的视频编码. 1. 安装OpenCV $ pip install opencv-python 建议在python虚拟环境下安装 ...

  7. Python爬取网易云音乐歌手歌曲和歌单

    仅供学习参考 Python爬取网易云音乐网易云音乐歌手歌曲和歌单,并下载到本地 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做 ...

  8. 程序员软件开发最好的IDE集成工具eclipse各个版本的详细介绍。详细介绍,送给初学者的朋友

    对于刚接触软件开发的初学者,在下载eclipse时,对官网上面提供的各种版本的选择犹豫不决.下面将对常用的几个版本进行介绍. Eclipse版本 Eclipse Standard 该版本是eclips ...

  9. unity 真机调试

    [Unity3D]Android和ios真机调试测Profiler http://blog.csdn.net/swj524152416/article/details/53466413 Unity5. ...

  10. Spine学习八 - 幻影特效

    Spine支持一些自带的特效,这些特效,不需要在spine中制作,而只是通过在unity中添加一些脚本便可实现. 这里先讲解一个比较使用又酷炫的效果,幻影特效: 1. 首先,在SkeletonAnim ...