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 ...
随机推荐
- 安国AU6989主控 + K9GBG08U0A(NAND) 制作4GB闪存驱动器
文档标识符:AU6989_FLASH-DRIVE_D-P8 作者:DLHC 最后修改日期:2020.8.22 本文链接: https://www.cnblogs.com/DLHC-TECH/p/AU6 ...
- 谱聚类的python实现
什么是谱聚类? 就是找到一个合适的切割点将图进行切割,核心思想就是: 使得切割的边的权重和最小,对于无向图而言就是切割的边数最少,如上所示.但是,切割的时候可能会存在局部最优,有以下两种方法: (1) ...
- 如何在Linux上使用scp命令进行服务器之间的文件/目录传输
1. 本地上传文件到远程: scp [local_file_path] [username]@[server_ip]:[remote_dir] 2. 本地上传目录到远程: scp -r [local_ ...
- python 报错错误集合——更新中
1. #!/usr/bin/env python # -*- coding:utf-8 -*- 'one #报错 File "C:\Users\shuxiu\Desktop\test.py& ...
- Oracle - Flashback standby after resetlogs on primary
一.概述 本文将给大家介绍主库使用rman做不完全恢复后,备库如何通过flashback,继续同步 二.正式实验 本次实验采用的是oracle 11g 单实例 + oracle 11g 单实例dg 1 ...
- 漏洞重温之sql注入(五)
漏洞重温之sql注入(五) sqli-labs通关之旅 填坑来了! Less-17 首先,17关,我们先查看一下页面,发现网页正中间是一个登录框. 显然,该关卡的注入应该为post型. 直接查看源码. ...
- springboot之对之前的补充
Spring Cloud 初级 一. Spring Boot 回顾 1 什么是 Spring Boot? Spring Boot 是在 Spring 的基础之上产生的(确切的说是在 Sprin ...
- 也谈基于Web的含工作流项目的一般开发流程
项目包含的通用模块代码等我有时间一并剥离贡献出来(基于WebSocket的通知引擎,工作流整合模块,自定义表单,基于RBAC权限设计),最近太忙了,Web项目有一段时间没碰,有点生疏的感觉,主要在忙G ...
- xmind8 破解激活教程
这里以windows为例来演示,其它操作系统需根据情况修改相应步骤. 一.下载安装包 首先去xmind国外官网下载对应操作系统的安装包,国内官网的那个是有残缺的,不支持破解. 官网下载链接 二.下载破 ...
- 如何通过seo技术提高网站对用户的友好度
http://www.wocaoseo.com/thread-129-1-1.html 今天的天气又是29度,眼看着满大街的人都穿着短袖和衬衣了,自己也再不能穿个厚厚的外套出去了,要不会被别人笑 ...