Java随谈(三)如何创建好一个对象?
本文推荐阅读时间30分钟
大家都知道,在编写Java程序里,一般就是处理各种各样的对象,那么,你知道一共有多少种创建对象的方式吗?
希望大家能稍微思考一下再往下翻。
答案是4种
- new 一个对象
- 反射一个类实例化一个对象(反射类和反射构造方法)
- clone 一个对象
- 反序列化一个对象
前两者调用了构造方法,后两者没有调用。
其中,日常使用中,最为常见的是使用new关键字创建对象;而在框架之中,最常用的是反射来控制对象生成。
下面详细地梳理常见的new对象的逻辑
- 若编写一个新的类,此时没有任何额外的需求时,采用最简单的构造方法即可。
- 若对象属性很多,但其中必传属性不多,可以使用set设置属性,或者重叠构造器模式。
- 若对象的属性和方法的传参类似,可以使用org.springframework.beans.BeanUtils.copyProperties()方法搭配set方法来设置参数。
- 若对象需要有一些特殊功能,比如单例,能够缓存等,可以使用静态工厂方法。
- 若对象需要一次性构建(创建不可变对象),使用建造者模式。
- 若对象为底层资源,会被各种方法依赖,使用依赖注入。
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随谈(三)如何创建好一个对象?的更多相关文章
- 【Java 线程的深入研究1】Java 提供了三种创建线程的方法
Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...
- Java 数组的三种创建方法,数组拷贝方法
public static void main(String[] args) {//创建数组的第一种方法int[] arr=new int[6];int intValue=arr[5];//Syste ...
- Java 数组的三种创建方法
public static void main(String[] args) { //创建数组的第一种方法 int[] arr=new int[6]; int intValue=arr[5]; //S ...
- 《java多线程——线程简介与其创建(1)》
Java 给多线程编程提供了内置的支持. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开 ...
- Java多线程(三)如何创建线程
点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...
- “全栈2019”Java多线程第三章:创建多线程之实现Runnable接口
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java 网络编程(三) 创建和使用URL访问网络上的资源
链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951877.html 创建和使用URL访问网络上的资源 URL(Uniform Reso ...
- 在Java中谈尾递归--尾递归和垃圾回收的比较(转载)
我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...
- java学习(三)
学号 20189214 <Java程序设计>第三周学习总结 教材学习内容总结 核心类 java.lang.Object 所有的类都直接派生自这个类. java.lang.String St ...
随机推荐
- xfs文件系统修复方法
1. 前言首先尝试mount和umount文件系统,以便重放日志,修复文件系统,如果不行,再进行如下操作.fdisk -l 查看硬盘分区情况mount -l 查看文件系统挂载情况df -h 查看文件系 ...
- Java多线程_同步工具CountDownLatch
概念:CountDownLatch是多线程里面一个类似于计数器的高级同步工具,它的初始值代表线程的数量,当一个线程完成了任务后,CountDownLatch的值就减1,当值为0的时候,代表所有线程完成 ...
- JAVA虚拟机故障诊断总结
一.JAVA运行时数据区 1.堆(-Xmx与-Xms):所有线程共享. 目的:用来存放对象实例.所有对象实例和数组都要在堆上分配内存.JAVA堆是垃圾收集器管理的主要区域 ...
- 重温Java Web的技术细节
目录 一.背景 二.请求与响应 2.1.Http请求 2.2.Http响应 三.ServletConfig 3.1 测试ServletConfig参数 四.ServletContext 4.1 测试S ...
- unity3d屏幕截图功能
function OnGUI(){ if(GUI.Button(Rect(Screen.width*0.5-50,Screen.height*0.5-50,100,100),"screen& ...
- Shader 的 Blend
Blend SrcAlpha OneMinusSrcAlpha //alpha blending Blend One OneMinusSrcAlpha //premultiplied alpha bl ...
- HDU - 1272-小希的迷宫(连通图+环的判断)
上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了 ...
- 如何让css样式只在当前组件起作用?
当前组件<style>写成<style scoped>
- javascript面试题(二)
24. function foo() { } var oldName = foo.name; foo.name = "bar"; [oldName, foo.name] // [f ...
- 20190923-06Linux文件权限类 000 014
文件属性 Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限.为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定.在Linux ...