本文推荐阅读时间30分钟

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

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

答案是4种

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

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

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

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

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

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

  1. public class Order {
  2. private String code;
  3. private List<String> offers;
  4. private Map<String, Object> features;
  5. public Order() {
  6. }
  7. public Order(String code, List<String> offers, Map<String, Object> features) {
  8. this.code = code;
  9. this.offers = offers;
  10. this.features = features;
  11. }
  12. }

2.1 重叠构造器模式

  1. public class Order {
  2. // not null!
  3. private String code;
  4. private List<String> offers;
  5. private Map<String, Object> features;
  6. //传入code, offers设为空集合, features设为空表
  7. public Order(String code) {
  8. this(code, new ArrayList<>(), new HashMap<>());
  9. }
  10. //传入code, offers, features设为空表
  11. public Order(String code, List<String> offers) {
  12. this(code, offers, new HashMap<>());
  13. }
  14. //传入code,features,offers设为空集合
  15. public Order(String code, Map<String, Object> features) {
  16. this(code, new ArrayList<>(), features);
  17. }
  18. //传入code, offers, features
  19. public Order(String code, List<String> offers, Map<String, Object> features) {
  20. this.code = code;
  21. this.offers = offers;
  22. this.features = features;
  23. }
  24. }

2.2 set设置属性

  1. public class Order {
  2. private String code;
  3. private List<String> offers;
  4. private Map<String, Object> features;
  5.  
  6. public String getCode() {
  7. return code;
  8. }
  9. public void setCode(String code) {
  10. this.code = code;
  11. }
  12. public List<String> getOffers() {
  13. return offers;
  14. }
  15. public void setOffers(List<String> offers) {
  16. this.offers = offers;
  17. }
  18. public Map<String, Object> getFeatures() {
  19. return features;
  20. }
  21. public void setFeatures(Map<String, Object> features) {
  22. this.features = features;
  23. }
  24. }

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

  1. //为省略代码量,使用lombok的@Data
  2.  
  3. //Order.java
  4. @Data
  5. public class Order {
  6. private String code;
  7. private List<String> offers;
  8. private Map<String, Object> features;
  9. }
  10.  
  11. //FooModel.java
  12. //和Order.java的属性一致
  13. @Data
  14. public class FooModel {
  15. private String code;
  16. private List<String> offers;
  17. private Map<String, Object> features;
  18. }
  19.  
  20. //FooTest.class
  21.  
  22. import org.springframework.beans.BeanUtils;
  23.  
  24. public class FooTest {
  25. public void handleFoo(FooModel model) {
  26. Order order = new Order();
  27. BeanUtils.copyProperties(model, order);
  28. //处理order对象
  29. }
  30. }

4.1 静态工厂方法单例对象

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

4.2 静态工厂方法缓存对象

  1. /**
  2. * 下面以经典的Boolean.java来举例
  3. * Boolean类创建了两个常量属性,TRUE和FALSE
  4. * 在调用valueOf时使用这个缓存
  5. */
  6. public final class Boolean implements java.io.Serializable,
  7. Comparable<Boolean>
  8. {
  9. //缓存 真
  10. public static final Boolean TRUE = new Boolean(true);
  11. //缓存 假
  12. public static final Boolean FALSE = new Boolean(false);
  13.  
  14. private final boolean value;
  15.  
  16. public Boolean(boolean value) {
  17. this.value = value;
  18. }
  19.  
  20. //返回缓存值,不新创建对象
  21. public static Boolean valueOf(boolean b) {
  22. return (b ? TRUE : FALSE);
  23. }
  24. }

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

  1. public class Order {
  2. private String code;
  3. private List<String> offers;
  4. private Map<String, Object> features;
  5.  
  6. public static Builder builder() {
  7. return new Builder();
  8. }
  9. //私有化构造方法,只提供给Builder.build()使用
  10. private Order(String code, List<String> offers, Map<String, Object> features) {
  11. this.code = code;
  12. this.offers = offers;
  13. this.features = features;
  14. }
  15.  
  16. public String toString() {
  17. return "Order(code=" + this.code + ", offers=" + this.offers + ", features=" + this.features + ")";
  18. }
  19.  
  20. public static class Builder {
  21. private String code;
  22. private List<String> offers;
  23. private Map<String, Object> features;
  24.  
  25. public Builder code(String code) {
  26. this.code = code;
  27. return this;
  28. }
  29. public Builder offers(List<String> offers) {
  30. this.offers = offers;
  31. return this;
  32. }
  33. public Builder offer(String offer) {
  34. if (null == this.offers) {
  35. this.offers = new ArrayList<>();
  36. }
  37. this.offers.add(offer);
  38. return this;
  39. }
  40. public Builder features(Map<String, Object> features) {
  41. this.features = features;
  42. return this;
  43. }
  44. public Builder feature(String key, Object value) {
  45. if (null == this.features) {
  46. this.features = new HashMap<>();
  47. }
  48. this.features.put(key, value);
  49. return this;
  50. }
  51. public Order build() {
  52. return new Order(this.code, this.offers, this.features);
  53. }
  54. }
  55.  
  56. public static void main(String[] args) {
  57. Order order = Order.builder()
  58. .code("1234")
  59. .offer("满100减5")
  60. .offer("满200减15")
  61. .feature("color", "white")
  62. .feature("category", "shirt")
  63. .build();
  64. System.out.println(order);
  65. }
  66. }
  67.  
  68. /** 输出
  69. Order(code=1234, offers=[满100减5, 满200减15], features={color=white, category=shirt})
  70.  
  71. Process finished with exit code 0
  72. */

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

函数式接口和泛型构造器

  1. @FunctionalInterface
  2. public interface KeyValueConsumer<T, K, V> {
  3.  
  4. void accept(T t, K k, V v);
  5.  
  6. default KeyValueConsumer<T, K, V> andThen(KeyValueConsumer<? super T, ? super K, ? super V> after) {
  7. Objects.requireNonNull(after);
  8. return (t, k, v) -> {
  9. accept(t, k, v);
  10. after.accept(t, k, v);
  11. };
  12. }
  13. }
  14.  
  15. public class GenericBuilder<T> {
  16. private final Supplier<T> instantiator;
  17. private List<Consumer<T>> instantiatorModifiers = new ArrayList<>();
  18. private List<Consumer<T>> keyValueModifiers = new ArrayList<>();
  19. public GenericBuilder(Supplier<T> instantiator) {
  20. this.instantiator = instantiator;
  21. }
  22. public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
  23. return new GenericBuilder<T>(instantiator);
  24. }
  25. public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
  26. Consumer<T> c = instance -> consumer.accept(instance, value);
  27. instantiatorModifiers.add(c);
  28. return this;
  29. }
  30. public <K, V> GenericBuilder<T> with(KeyValueConsumer<T, K, V> consumer, K key, V value) {
  31. Consumer<T> c = instance -> consumer.accept(instance, key, value);
  32. keyValueModifiers.add(c);
  33. return this;
  34. }
  35. public T build() {
  36. T value = instantiator.get();
  37. instantiatorModifiers.forEach(modifier -> modifier.accept(value));
  38. keyValueModifiers.forEach(keyValueModifier -> keyValueModifier.accept(value));
  39. instantiatorModifiers.clear();
  40. keyValueModifiers.clear();
  41. return value;
  42. }
  43. }

实际操作类

  1. package com.example.demo.bean;
  2.  
  3. import lombok.Builder;
  4. import lombok.Singular;
  5. import lombok.ToString;
  6.  
  7. import java.util.*;
  8.  
  9. public class Order {
  10. private String code;
  11. private List<String> offers;
  12. private Map<String, Object> features;
  13.  
  14. //省略无参构造方法,set、get,toString方法
  15.  
  16. public void addOffer(String offer) {
  17. offers = Optional.ofNullable(offers)
  18. .orElseGet(ArrayList::new);
  19. offers.add(offer);
  20. }
  21.  
  22. public <T> void addFeature(String key, T value) {
  23. features = Optional.ofNullable(features)
  24. .orElseGet(HashMap::new);
  25. features.put(key, value);
  26. }
  27.  
  28. public static void main(String[] args) {
  29. Order order = GenericBuilder.of(Order::new)
  30. .with(Order::setCode, "1234")
  31. .with(Order::addOffer, "满200减15")
  32. .with(Order::addOffer, "满200减15")
  33. .with(Order::addFeature, "color", "white")
  34. .with(Order::addFeature, "category", "shirt").build();
  35. System.out.println(order);
  36. }
  37. }
  38.  
  39. /** 输出
  40. Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt})
  41.  
  42. Process finished with exit code 0
  43. */

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

  1. @ToString
  2. @Builder
  3. public class Order {
  4. private String code;
  5. @Singular
  6. private List<String> offers;
  7. @Singular
  8. private Map<String, Object> features;
  9.  
  10. public static void main(String[] args) {
  11. Order order = Order.builder()
  12. .code("1234")
  13. .offer("满100减5")
  14. .offer("满200减15")
  15. .feature("color", "white")
  16. .feature("category", "shirt")
  17. .build();
  18. System.out.println(order);
  19. }
  20. }
  21.  
  22. /** 输出
  23. Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt})
  24.  
  25. Process finished with exit code 0
  26. */

6.1 依赖注入

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

  1. @RestController
  2. public class DemoController {
  3. //自动注入demo的服务
  4. @Autowired
  5. private DemoService demoService;
  6.  
  7. @GetMapping
  8. public String getDemo() {
  9. return demoService.get();
  10. }

建造者模式来源于 如何实现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. xfs文件系统修复方法

    1. 前言首先尝试mount和umount文件系统,以便重放日志,修复文件系统,如果不行,再进行如下操作.fdisk -l 查看硬盘分区情况mount -l 查看文件系统挂载情况df -h 查看文件系 ...

  2. Java多线程_同步工具CountDownLatch

    概念:CountDownLatch是多线程里面一个类似于计数器的高级同步工具,它的初始值代表线程的数量,当一个线程完成了任务后,CountDownLatch的值就减1,当值为0的时候,代表所有线程完成 ...

  3. JAVA虚拟机故障诊断总结

    一.JAVA运行时数据区               1.堆(-Xmx与-Xms):所有线程共享.  目的:用来存放对象实例.所有对象实例和数组都要在堆上分配内存.JAVA堆是垃圾收集器管理的主要区域 ...

  4. 重温Java Web的技术细节

    目录 一.背景 二.请求与响应 2.1.Http请求 2.2.Http响应 三.ServletConfig 3.1 测试ServletConfig参数 四.ServletContext 4.1 测试S ...

  5. unity3d屏幕截图功能

    function OnGUI(){ if(GUI.Button(Rect(Screen.width*0.5-50,Screen.height*0.5-50,100,100),"screen& ...

  6. Shader 的 Blend

    Blend SrcAlpha OneMinusSrcAlpha //alpha blending Blend One OneMinusSrcAlpha //premultiplied alpha bl ...

  7. HDU - 1272-小希的迷宫(连通图+环的判断)

    上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了 ...

  8. 如何让css样式只在当前组件起作用?

    当前组件<style>写成<style  scoped>

  9. javascript面试题(二)

    24. function foo() { } var oldName = foo.name; foo.name = "bar"; [oldName, foo.name] // [f ...

  10. 20190923-06Linux文件权限类 000 014

    文件属性 Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限.为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定.在Linux ...