「 Java开发规范 」10人小团队Java开发规范参考这篇就够了!

简介: Kent Beck 的简单设计四原则非常好地来指导我们的如何写出优秀的代码,如何有效地判断我们的代码是优秀的。通过所有测试(Passes its tests):强调的是外部需求,这是代码实现最重要的尽可能消除重复 (Minimizes duplication):代码的模块架构设计,保证代码的正交性,保证代码更容易修改尽可能清晰表达 (Maximizes clarity):代码的可阅读性,保证代码是容易阅读的更少代码元素 (Has fewer elements):保证代码是简洁的,在简洁和表达力之间,我们更看重表达力

一、编程规范

1、好代码的原则

Kent Beck 的简单设计四原则非常好地来指导我们的如何写出优秀的代码,如何有效地判断我们的代码是优秀的。

通过所有测试(Passes its tests):强调的是外部需求,这是代码实现最重要的
尽可能消除重复 (Minimizes duplication):代码的模块架构设计,保证代码的正交性,保证代码更容易修改
尽可能清晰表达 (Maximizes clarity):代码的可阅读性,保证代码是容易阅读的
更少代码元素 (Has fewer elements):保证代码是简洁的,在简洁和表达力之间,我们更看重表达力

以上四个原则的重要程度依次降低, 这组定义被称做简单设计原则。

2、项目命名规范

全部采用小写方式, 以中划线分隔。

正例:mall-management-system / order-service-client / user-api

反例:mall_management-system / mallManagementSystem / orderServiceClient

3、TODO/FIXME 规范

TODO/TBD(to be determined) 注释一般用来描述已知待改进、待补充的修改点,并且加上作者名称。  FIXME 注释一般用来描述已知缺陷,它们都应该有统一风格,方便文本搜索统一处理。如:

// TODO <author-name>: 补充XX处理

// FIXME <author-name>: XX缺陷

4、方法参数规范

无论是 controller,service,manager,dao 亦或是其他的代码,每个方法最多 3 个参数,如果超出 3 个参数的话,要封装成 javabean 对象。  

  1. 方便他人调用,降低出错几率。尤其是当参数是同一种类型,仅仅依靠顺序区分,稍有不慎便是灾难性后果,而且排查起来也极其恶心。  
  2. 保持代码整洁、清晰度。当一个个方法里充斥着一堆堆参数的时候,再坚强的人,也会身心疲惫。

反例:

/*** 使用证书加密数据工具方法** @param param* @param password 加密密码* @param priCert 私钥* @param pubCert 公钥* @return 返回加密后的字符串*/publicStringsignEnvelop(JdRequestParamparam, Stringpassword, StringpriCert, StringpubCert){}

5、注释规范

5-1、注释和代码一样重要

注释是我们披荆斩棘历经磨难翻越需求这座大山时,留下的踪迹和收获的经验教训,这些宝贵的知识除了证明我们曾经存在过,也提醒着后来的人们殷鉴不远、继往开来。

注释除了说明作用、逻辑之外。还有一个很重要的原因:当业务逻辑过于复杂,代码过于庞大的时候,注释就变成了一道道美化环境、分离与整理逻辑思路的路标。这是很重要的一点,它能有效得帮助我们免于陷入代码与业务逻辑的泥沼之中。

正例:

/*** 开始抽奖方法* 保存中奖信息、奖励用户积分等* @param luckDrawDTO* @return ResponseDTO 返回中奖信息*/publicResponseDTO<String>startLuckDraw(LuckDrawDTOluckDrawDTO) {
// -------------- 1、校验抽奖活动基本信息 ------------------------xxx伪代码一顿操作// -------------- 2、新增抽奖记录 -------------------------------xxx伪代码一顿操作// -------------- 3、如果需要消耗积分,则扣除钢镚积分 -------------xxx伪代码一顿操作// -------------- 4、获取奖品信息,开始翻滚吧 --------------------xxx伪代码一顿操作returnResponseDTO.succ(luckDrawPrizeVO);
}

5-2、注释和代码的一致性

注释并不是越多越好,当注释过多,维护代码的同时,还需要维护注释,不仅变成了一种负担,也与我们当初添加注释的初衷背道而驰。  

首先:大家应该通过清晰的逻辑架构,好的变量命名来提高代码可读性;需要的时候,才辅以注释说明。注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,按需注释。注释内容要简洁、明了、无二义性,信息全面且不冗余。

其次:无论是修改、复制代码时,都要仔细核对注释内容是否正确。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,会让阅读者迷惑、费解,甚至误解。

反例:

// 查询部门EmployeeDTOemployee=employeeDao.listByDeptId(deptId);

5-3、方法注释

方法要尽量通过方法名自解释,不要写无用、信息冗余的方法头,不要写空有格式的方法头注释。

方法头注释内容可选,但不限于:功能说明、返回值,用法、算法实现等等。尤其是对外的方法接口声明,其注释,应当将重要、有用的信息表达清楚。

正例:

/*** 解析转换时间字符串为 LocalDate 时间类* 调用前必须校验字符串格式 否则可能造成解析失败的错误异常** @param dateStr 必须是 yyyy-MM-dd 格式的字符串* @return LocalDate*/publicstaticLocalDateparseYMD(StringdateStr){}

反例:

/*** 校验对象** @param t* @return String*/publicstatic<T>StringcheckObj(Tt);

反例中出现的问题:

方法注释没有说明具体的作用、使用事项。
参数、返回值,空有格式没内容。这是非常重要一点,任何人调用任何方法之前都需要知道方法对参数的要求,以及返回值是什么。

二、项目规范

1、代码目录结构

统一的目录结构是所有项目的基础。

src                               源码目录

|-- common                            各个项目的通用类库

|-- config                            项目的配置信息

|-- constant                          全局公共常量

|-- handler                           全局处理器

|-- interceptor                       全局连接器

|-- listener                          全局监听器

|-- module                            各个业务

|-- |--- employee                         员工模块

|-- |--- role                             角色模块

|-- |--- login                            登录模块

|-- third                             三方服务,比如redis, oss,微信sdk等等

|-- util                              全局工具类

|-- Application.java                  启动类

2、common 目录规范

common 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。

src 源码目录

|-- common 各个项目的通用类库

|-- |--- anno          通用注解,比如权限,登录等等

|-- |--- constant      通用常量,比如 ResponseCodeConst

|-- |--- domain        全局的 javabean,比如 BaseEntity,PageParamDTO 等

|-- |--- exception     全局异常,如 BusinessException

|-- |--- json          json 类库,如 LongJsonDeserializer,LongJsonSerializer

|-- |--- swagger       swagger 文档

|-- |--- validator     适合各个项目的通用 validator,如 CheckEnum,CheckBigDecimal 等

3、config 目录规范

config 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。

src                               源码目录

|-- config                            项目的所有配置信息

|-- |--- MvcConfig                    mvc的相关配置,如interceptor,filter等

|-- |--- DataSourceConfig             数据库连接池的配置

|-- |--- MybatisConfig                mybatis的配置

|-- |--- ....                         其他

4、module 目录规范

module 目录里写项目的各个业务,每个业务一个独立的顶级文件夹,在文件里进行 mvc 的相关划分。其中,domain 包里存放 entity, dto, vo,bo 等 javabean 对象

src

|-- module                         所有业务模块

|-- |-- role                          角色模块

|-- |-- |--RoleController.java              controller

|-- |-- |--RoleConst.java                   role相关的常量

|-- |-- |--RoleService.java                 service

|-- |-- |--RoleDao.java                     dao

|-- |-- |--domain                           domain

|-- |-- |-- |-- RoleEntity.java                  表对应实体

|-- |-- |-- |-- RoleDTO.java                     dto对象

|-- |-- |-- |-- RoleVO.java                      返回对象

|-- |-- employee                      员工模块

|-- |-- login                         登录模块

|-- |-- email                         邮件模块

|-- |-- ....                          其他

5、 domain 包中的 javabean 命名规范

1) javabean 的整体要求:

不得有任何的业务逻辑或者计算
基本数据类型必须使用包装类型(Integer, Double、Boolean 等)
不允许有任何的默认值
每个属性必须添加注释,并且必须使用多行注释。
必须使用 lombok 简化 getter/setter 方法
建议对象使用 lombok 的 @Builder ,@AllArgsConstructor,同时使用这两个注解,简化对象构造方法以及set方法。

正例:

@Builder@NoArgsConstructor@DatapublicclassDemoDTO {
privateStringname;
privateIntegerage;
}

 

// 使用示例:DemoDTOdemo=DemoDTO.builder()
                .name("yeqiu")
                .age(66)
                .build();

 

2)数据对象;XxxxEntity,要求:

以 Entity 为结尾(阿里是为 DO 为结尾)
Xxxx 与数据库表名保持一致
类中字段要与数据库字段保持一致,不能缺失或者多余
类中的每个字段添加注释,并与数据库注释保持一致
不允许有组合
项目内的日期类型必须统一,建议使用 java.util.Date,java.sql.Timestamp,java.time.LocalDateTime 其中只一。

3)传输对象;XxxxDTO,要求:

不可以继承自 Entity
DTO 可以继承、组合其他 DTO,VO,BO 等对象
DTO 只能用于前端、RPC 的请求参数

3)视图对象;XxxxVO,要求:

不可继承自 Entity
VO 可以继承、组合其他 DTO,VO,BO 等对象
VO 只能用于返回前端、rpc 的业务数据封装对象

4)业务对象 BO,要求:

不可以继承自 Entity
BO 对象只能用于 service,manager,dao 层,不得用于 controller 层

三、MVC 规范

1、整体分层

controller 层
service 层
manager 层
dao 层

2、 controller 层规范

1) 只允许在 method 上添加 RequestMapping 注解,不允许加在 class 上(为了方便的查找 url,放到 url 不能一次性查找出来)

正例:

@RestControllerpublicclassDepartmentController {
@GetMapping("/department/list")
publicResponseDTO<List<DepartmentVO>>listDepartment() {
returndepartmentService.listDepartment();
    }
}

反例:

@RequestMapping ("/department")
publicclassDepartmentController {
@GetMapping("/list")
publicResponseDTO<List<DepartmentVO>>listDepartment() {
returndepartmentService.listDepartment();
    }
}

2)不推荐使用 rest 命名 url, 只能使用 get/post 方法。url 命名上规范如下:

虽然 Rest 大法好,但是有时并不能一眼根据 url 看出来是什么操作,所以我们选择了后者,这个没有对与错,只有哪个更适合我们的团队。

/业务模块/子模块/动作

正例:

GET  /department/get/{id}      查询某个部门详细信息
POST /department/query         复杂查询
POST /department/add           添加部门
POST /department/update        更新部门
GET  /department/delete/{id}   删除部门

3)每个方法必须添加 swagger 文档注解 @ApiOperation ,并填写接口描述信息,描述最后必须加上作者信息 @author 哪吒

正例:

@ApiOperation("更新部门信息 @author 哪吒")
@PostMapping("/department/update")
publicResponseDTO<String>updateDepartment(@Valid@RequestBodyDeptUpdateDTOdeptUpdateDTO) {
returndepartmentService.updateDepartment(deptUpdateDTO);
}


4)controller 负责协同和委派业务,充当路由的角色,每个方法要保持简洁:

  • 不做任何的业务逻辑操作
  • 不做任何的参数、业务校验,参数校验只允许使用@Valid 注解做简单的校验
  • 不做任何的数据组合、拼装、赋值等操作

正例:

   

@ApiOperation("添加部门 @author 哪吒")
@PostMapping("/department/add")
publicResponseDTO<String>addDepartment(@Valid@RequestBodyDepartmentCreateDTOdepartmentCreateDTO) {
returndepartmentService.addDepartment(departmentCreateDTO);
}

5)只能在 controller 层获取当前请求用户,并传递给 service 层。

因为获取当前请求用户是从 ThreadLocal 里获取取的,在 service、manager、dao 层极有可能是其他非 request 线程调用,会出现 null 的情况,尽量避免

   

@ApiOperation("添加员工 @author yandanyang")
@PostMapping("/employee/add")
publicResponseDTO<String>addEmployee(@Valid@RequestBodyEmployeeAddDTOemployeeAddDTO) {
LoginTokenBOrequestToken=SmartRequestTokenUtil.getRequestUser();
returnemployeeService.addEmployee(employeeAddDTO, requestToken);
}

3、 service 层规范

1)合理拆分 service 文件,如果业务较大,请拆分为多个 service。

如订单业务,所有业务都写到 OrderService 中会导致文件过大,故需要进行拆分如下:

OrderQueryService 订单查询业务
OrderCreateService 订单新建业务
OrderDeliverService 订单发货业务
OrderValidatorService 订单验证业务

2)谨慎处理 @Transactional 事务注解的使用,不要简单对 service 的方法添加个 @Transactional 注解就觉得万事大吉了。应当合并对数据库的操作,尽量减少添加了@Transactional方法内的业务逻辑。  @Transactional 注解内的 rollbackFor 值必须使用异常的基类 Throwable.class

对于@Transactional 注解,当 spring 遇到该注解时,会自动从数据库连接池中获取 connection,并开启事务然后绑定到 ThreadLocal 上,如果业务并没有进入到最终的 操作数据库环节,那么就没有必要获取连接并开启事务,应该直接将 connection 返回给数据库连接池,供其他使用(比较难以讲解清楚,如果不懂的话就主动去问)。

反例:

@Transactional(rollbackFor=Throwable.class)
publicResponseDTO<String>upOrDown(LongdepartmentId, LongswapId) {
// 验证 1DepartmentEntitydepartmentEntity=departmentDao.selectById(departmentId);
if (departmentEntity==null) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
    }
// 验证 2DepartmentEntityswapEntity=departmentDao.selectById(swapId);
if (swapEntity==null) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
    }
// 验证 3Longcount=employeeDao.countByDepartmentId(departmentId)
if (count!=null&&count>0) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);
        }
// 操作数据库 4LongdepartmentSort=departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
returnResponseDTO.succ();
}

以上代码前三步都是使用 connection 进行验证操作,由于方法上有@Transactional 注解,所以这三个验证都是使用的同一个 connection。

若对于复杂业务、复杂的验证逻辑,会导致整个验证过程始终占用该 connection 连接,占用时间可能会很长,直至方法结束,connection 才会交还给数据库连接池。

对于复杂业务的不可预计的情况,长时间占用同一个 connection 连接不是好的事情,应该尽量缩短占用时间。

正例:

   DepartmentService.java

publicResponseDTO<String>upOrDown(LongdepartmentId, LongswapId) {
DepartmentEntitydepartmentEntity=departmentDao.selectById(departmentId);
if (departmentEntity==null) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
    }
DepartmentEntityswapEntity=departmentDao.selectById(swapId);
if (swapEntity==null) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);
    }
Longcount=employeeDao.countByDepartmentId(departmentId)
if (count!=null&&count>0) {
returnResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);
        }
departmentManager.upOrDown(departmentSort,swapEntity);
returnResponseDTO.succ();
}


   DepartmentManager.java

@Transactional(rollbackFor=Throwable.class)
publicvoidupOrDown(DepartmentEntitydepartmentEntity ,DepartmentEntityswapEntity){
LongdepartmentSort=departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
}

 

将数据在 service 层准备好,然后传递给 manager 层,由 manager 层添加@Transactional 进行数据库操作。

3)需要注意的是:注解 @Transactional 事务在类的内部方法调用是不会生效的

反例:如果发生异常,saveData方法上的事务注解并不会起作用

@ServicepublicclassOrderService{
publicvoidcreateOrder(OrderCreateDTOcreateDTO){
this.saveData(createDTO);
    }
@Transactional(rollbackFor=Throwable.class)
publicvoidsaveData(OrderCreateDTOcreateDTO){
orderDao.insert(createDTO);
    }
}

Spring采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。只有在代理对象之间进行调用时,可以触发切面逻辑。而在同一个class中,方法A调用方法B,调用的是原对象的方法,而不通过代理对象。所以Spring无法拦截到这次调用,也就无法通过注解保证事务了。简单来说,在同一个类中的方法调用,不会被方法拦截器拦截到,因此事务不会起作用。

解决方案:

  1. 可以将方法放入另一个类,如新增 manager层,通过spring注入,这样符合了在对象之间调用的条件。
  2. 启动类添加@EnableAspectJAutoProxy(exposeProxy = true),方法内使用AopContext.currentProxy()获得代理类,使用事务。

SpringBootApplication.java

@EnableAspectJAutoProxy(exposeProxy=true)
@SpringBootApplicationpublicclassSpringBootApplication {}

 

OrderService.java

publicvoidcreateOrder(OrderCreateDTOcreateDTO){
OrderServiceorderService= (OrderService)AopContext.currentProxy();
orderService.saveData(createDTO);
}

4)service是具体的业务处理逻辑服务层,尽量避免将web层某些参数传递到service中。  

反例:

publicResponseDTO<String>handlePinganRequest(HttpServletRequestrequest){
InputStreamReaderinputStreamReader=newInputStreamReader(request.getInputStream(), "GBK");
BufferedReaderreader=newBufferedReader(inputStreamReader);
StringBuildersb=newStringBuilder();
Stringstr;
while ((str=reader.readLine()) !=null) {
sb.append(str);
    }
if(!JSON.isValid(msg)){
returnResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
    }
PinganMsgDTOPinganMsgDTO=JSON.parseObject(msg,PinganMsgDTO.class);
// 示例结束}

 

反例中出现的问题:

  • 反例中把 HttpServletRequest 传递到service中,是为了获取Request流中的字符信息,然后才是真正的业务处理。按照分层的初衷:将代码、业务逻辑解耦,正确的做法应该是handlePinganRequest方法将String字符作为参数直接处理业务,将从Request中获取字符的操作放入controller中。
  • 另一个坏处是不方便做单元测试,还得一个new一个HttpServletRequest并制造一个InputStream,然而这样做并不能模拟到真实的业务情景及数据。

4、 manager 层规范

manager 层的作用(引自《阿里 java 手册》):

对第三方平台封装的层,预处理返回结果及转化异常信息;Service层通用能力的下沉,如缓存方案、中间件通用处理;DAO层交互,对多个DAO的组合复用。

5、 dao 层规范

优先使用 mybatis-plus 框架。如果需要多个数据源操作的,可以选择使用 SmartDb 框架。

1)所有 Dao 继承自 BaseMapper

2)禁止使用 Mybatis-plus 的 Wrapper 条件构建器

3)禁止直接在 mybatis xml 中写死常量,应从 dao 中传入到 xml 中

3)建议不要使用星号 * 代替所有字段

正例:

NoticeDao.javaIntegernoticeCount(@Param("sendStatus") IntegersendStatus);
---------------------------------------------NoticeMapper.xml<selectid="noticeCount"resultType="integer">selectcount(1)
fromt_noticewheresend_status=#{sendStatus}
</select>

反例:

NoticeDao.javaIntegernoticeCount();
---------------------------------------------NoticeMapper.xml<selectid="noticeCount"resultType="integer">selectcount(1)
fromt_noticewheresend_status=0</select>

3)dao层方法命名规范

获取单个对象的方法用get做前缀。获取多个对象的方法用list做前缀。获取统计值的方法用count做前缀。插入的方法用save/insert做前缀。删除的方法用remove/delete做前缀。修改的方法用update做前缀。

建议:dao层方法命名尽量以sql语义命名,避免与业务关联。

正例:
List<PerformanceDTO> listByMonthAndItemId(@Param("month") String month, @Param("itemId") Integer itemId);
反例:
List<PerformanceDTO> getInternalData(@Param("month") String month, @Param("itemId") Integer itemId);

反例中出现的不规范操作:

get代表单个查询,批量查询的应该list开头。命名与业务关联,局限了dao方法的使用场景和范围,降低了方法的复用性,造成他人困惑以及重复造轮子。

6、boolean类型的属性命名规范

类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

这是阿里巴巴开发手册中的原文,我们团队的规定是:boolean 类型的类属性和数据表字段都统一使用 flag 结尾。虽然使用 isDeleted,is_deleted 从字面语义上更直观,但是比起可能出现的潜在错误,这点牺牲还是值得的。

正例:

deletedFlag,deleted_flag,onlineFlag,online_flag

四、数据库规范

1 建表规范

表必备三字段:id, create_time, update_time

id字段Long类型,单表自增,自增长度为1create_time字段datetime类型,默认值CURRENT_TIMESTAMPupdate_time字段datetime类型,默认值CURRENT_TIMESTAMP, OnupdateCURRENT_TIMESTAMP

2 枚举类表字段注释需要将所有枚举含义进行注释

修改或增加字段的状态描述,必须要及时同步更新注释。  如下表的 sync_status 字段 同步状态 0 未开始 1同步中 2同步成功 3失败

正例:

CREATETABLE`t_change_data` (
`id`BIGINT(20) UNSIGNEDNOTNULLAUTO_INCREMENT,
`sync_status`TINYINT(3) UNSIGNEDNOTNULLDEFAULT'0'COMMENT'同步状态 0 未开始 1同步中 2同步成功 3失败',
`sync_time`DATETIMENULLDEFAULTNULLCOMMENT'同步时间',
`create_time`DATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,
`update_time`DATETIMENULLDEFAULTNULLONUPDATECURRENT_TIMESTAMP,
PRIMARYKEY (`change_data_id`)
)

反例:

CREATETABLE`t_change_data` (
`id`BIGINT(20) UNSIGNEDNOTNULLAUTO_INCREMENT,
`sync_status`TINYINT(3) UNSIGNEDNOTNULLDEFAULT'0'COMMENT'同步状态 ',
`sync_time`DATETIMENULLDEFAULTNULLCOMMENT'同步时间',
`create_time`DATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,
`update_time`DATETIMENULLDEFAULTNULLONUPDATECURRENT_TIMESTAMP,
PRIMARYKEY (`change_data_id`)
)

3 合理结合业务给表字段添加索引和唯一索引

具体索引规范请参照《阿里巴巴 Java 开发手册》索引规约

五、其他

1、代码提交规范

提交前应该冷静、仔细检查一下,确保没有忘记加入版本控制或不应该提交的文件。
提交前应该先编译一次(idea里ctrl+F9),防止出现编译都报错的情况。
提交前先更新pull一次代码,提交前发生冲突要比提交后发生冲突容易解决的多。
提交前检查代码是否格式化,是否符合代码规范,无用的包引入、变量是否清除等等。
提交时检查注释是否准确简洁的表达出了本次提交的内容。

2、maven项目

pom禁止出现相同 groupId,artifactId 的依赖配置。
项目名称应该与 artifactId 保持一致。
定期检查jar包依赖关系,及时排除解决冲突的jar包。

3、保持项目整洁

使用git,必须添加 .gitignore 忽略配置文件。  不要提交与项目无关的内容文件:idea配置、target包等。

参考:本篇内容参考自开源社区,感谢前人的经验和付出,让我们可以有机会站在巨人的肩膀上眺望星辰大海。

相关文章
|
8天前
|
设计模式 安全 Java
面向对象编程的精髓:Java设计模式 - 原型模式(Prototype)完全参考手册
【4月更文挑战第7天】原型模式是OOP中的创建型设计模式,用于通过复制现有实例创建新实例,尤其适用于创建成本高或依赖其他对象的情况。它包括Prototype接口、ConcretePrototype实现和Client客户端角色。优点是性能优化、避免子类化和动态增加产品族。实现包括定义原型接口、实现具体原型和客户端调用克隆方法。最佳实践涉及确保克隆正确性、选择深拷贝或浅拷贝及考虑线程安全。但需注意克隆方法管理、性能开销和循环引用等问题。在Java中,实现Cloneable接口和覆盖clone方法可实现原型模式。
|
8天前
|
监控 前端开发 Java
Java从入门到精通:4.1.2参与实际项目——学习与团队成员协作,了解项目开发的流程和规范
Java从入门到精通:4.1.2参与实际项目——学习与团队成员协作,了解项目开发的流程和规范
|
8天前
|
JavaScript Java 测试技术
基于Java的学术团队管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的学术团队管理系统的设计与实现(源码+lw+部署文档+讲解等)
25 1
|
8天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
38 0
Java入门高频考查基础知识9(15问万字参考答案)
|
8天前
|
消息中间件 NoSQL 算法
Java入门高频考查基础知识8(18问1.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
50 0
Java入门高频考查基础知识8(18问1.5万字参考答案)
|
8天前
|
存储 安全 算法
Java入门高频考查基础知识7-深入挖掘Java集合框架的奇幻世界2(39题2.8万字参考答案)
Java 集合框架提供了一组实现了各种集合接口的类。这些集合类提供了对对象组进行存储、操作和检索的高效方式,并且是 Java 中最常用的数据结构之一。 Java 集合框架主要包括 Collection 和 Map 两个顶层接口,它们分别有各种实现类来满足不同的需求。 在 Collection 部分,包括 List、Set 和 Queue 接口,它们分别对应着有序列表、集合和队列这三种数据结构。常用的实现类包括 ArrayList、LinkedList、HashSet、TreeSet 等,它们提供了各自特
50 0
Java入门高频考查基础知识7-深入挖掘Java集合框架的奇幻世界2(39题2.8万字参考答案)
|
8天前
|
存储 安全 算法
Java入门高频考查基础知识6-深入挖掘Java集合框架的奇幻世界(45题3.6万字参考答案)
Java 集合框架提供了一组实现了各种集合接口的类。这些集合类提供了对对象组进行存储、操作和检索的高效方式,并且是 Java 中最常用的数据结构之一。 Java 集合框架主要包括 Collection 和 Map 两个顶层接口,它们分别有各种实现类来满足不同的需求。 在 Collection 部分,包括 List、Set 和 Queue 接口,它们分别对应着有序列表、集合和队列这三种数据结构。常用的实现类包括 ArrayList、LinkedList、HashSet、TreeSet 等,它们提供了各自特
57 0
|
8天前
|
存储 XML JavaScript
Java入门高频考查基础知识5(扎实技术基础应变一切变化-45题4.2万字参考答案)
数据结构是指在计算机中组织和存储数据的方式,它建立了数据元素之间的关系,以及对这些关系施加的操作。在程序设计中,数据结构是一种非常重要的概念,它对于实现高效的数据存储、检索和操作起着关键性的作用。逻辑结构逻辑结构是数据对象中数据元素之间的逻辑关系,包括线性结构(如数组、链表)、树形结构(如二叉树、平衡树)以及图形结构等。物理结构:物理结构是数据的逻辑结构在计算机中的存储形式,包括顺序存储结构和链式存储结构等。数据操作数据操作是指在一组数据上定义的操作,包括插入、删除、查找、排序等。
63 0
|
8天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
68 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
8天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
37 0