一、前言
很久没看到java内部类了,今天在审查代码时候,发现了java内部类,主要是内部类还嵌套了内部类。于是记录一下
二、java内部类的作用与优缺点
Java内部类,也称为嵌套类,是定义在另一个类(外部类)内部的类。内部类提供了将逻辑上相关的类组织在一起的方式,并增强了封装性。以下是内部类的主要作用及其优缺点:
内部类的作用:
-
封装性增强:内部类可以隐藏不希望从外部直接访问的类、成员变量或方法,从而增强了封装性。
-
代码组织:内部类可以将一些逻辑上紧密相关的类组织在一起,从而提高了代码的可读性和可维护性。
-
访问外部类的私有成员:内部类可以直接访问外部类的私有成员(包括私有字段、私有方法、私有内部类等),而无需通过getter或setter方法。
-
实现回调和事件处理:内部类常被用作回调和事件处理的机制,例如监听器接口的实现。
-
实现多继承:虽然Java不支持类的多继承,但可以通过内部类实现接口的多继承,从而间接实现多继承的效果。
内部类的优点:
-
提高代码的可读性和可维护性:通过将相关的类组织在一起,提高了代码的组织性和清晰度。
-
增加封装性:内部类可以限制对外部类的访问,进一步提高了封装性。
-
实现更灵活的设计:内部类可以实现一些特定的设计模式,如工厂模式、策略模式等,使代码更灵活。
内部类的缺点:
-
可读性下降:对于不熟悉内部类的人来说,阅读和理解代码可能会更加困难,因为内部类的结构相对复杂。
-
命名冲突:如果内部类与外部类或其他内部类具有相同的名称,可能会导致命名冲突和混淆。
-
内存消耗:由于内部类对象持有对外部类对象的隐式引用,因此可能会导致额外的内存消耗。
-
访问限制:静态内部类不能访问外部类的非静态成员,这可能会限制其用途。
-
匿名内部类的限制:匿名内部类虽然方便,但只能在定义时使用一次,且不能添加构造方法,这可能会限制其灵活性。
在使用内部类时,需要根据具体场景和需求权衡其优缺点,以做出合理的选择。
三、java内部类例子
其中里面就包含了内部类再嵌套内部类的做法,可阅读性非常差。
public class RequestOrderOperateModel {
private Long operId; // 操作员ID
private String operName; // 操作员名称
private List<OrderOperate> orderOperate; // 订单操作 (批量)
private String orderType; // 订单类型 200001: 商城消费主订单 200002: 支付订单 200003: 库存订单 200004: 配送订单
private String filterStoreOuCode; // 店铺权限过滤
private String filterStoreStandCode; // 店铺权限过滤 (标准编码)
private Boolean autoPickup; // 是否超时自动提货
private String refundRemark; // 退款原因
private String refundContactPhone; // 退款联系电话
@MethodAnnotation(description = "操作员ID")
public Long getOperId() {
return operId;
}
public void setOperId(Long operId) {
this.operId = operId;
}
@MethodAnnotation(description = "操作员名称")
public String getOperName() {
return operName;
}
public void setOperName(String operName) {
this.operName = operName;
}
@MethodAnnotation(description = "订单类型 200001: 商城消费主订单 200015: 支付订单 200016: 库存订单 200017: 配送订单")
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
@MethodAnnotation(description = "订单操作 (批量)")
public List<OrderOperate> getOrderOperate() {
return orderOperate;
}
public void setOrderOperate(List<OrderOperate> orderOperate) {
this.orderOperate = orderOperate;
}
@MethodAnnotation(description = "店铺权限过滤")
public String getFilterStoreOuCode() {
return filterStoreOuCode;
}
public void setFilterStoreOuCode(String filterStoreOuCode) {
this.filterStoreOuCode = filterStoreOuCode;
}
@MethodAnnotation(description = "店铺权限过滤 (标准编码)")
public String getFilterStoreStandCode() {
return filterStoreStandCode;
}
public void setFilterStoreStandCode(String filterStoreStandCode) {
this.filterStoreStandCode = filterStoreStandCode;
}
public Boolean getAutoPickup() {
return autoPickup;
}
public void setAutoPickup(Boolean autoPickup) {
this.autoPickup = autoPickup;
}
public String getRefundRemark() {
return refundRemark;
}
public void setRefundRemark(String refundRemark) {
this.refundRemark = refundRemark;
}
public String getRefundContactPhone() {
return refundContactPhone;
}
public void setRefundContactPhone(String refundContactPhone) {
this.refundContactPhone = refundContactPhone;
}
public static class OrderOperate {
private Long orderId; // 订单ID
private String userId; // 用户ID
private Long deliveryOrderId; // 配送单ID
private Long repairOrderId; // 售后单ID
private String interfaceOrderId; // 第三方订单ID
private Integer state; // 订单状态 (4待收货 6 拒收 9已完成 11已退款 12支付后取消 16待发货 17待备货)
private String expressName; // 快递公司名称 (修改为发货状态时使用)
private String expressCode; // 快递公司名称 (修改为发货状态时使用)
private String expressNo; // 快递公司单号 (修改为发货状态时使用)
private BigDecimal expressFreightAmount; // 快递配送运费金额
private String pickupCode; // 提货码 (自提单修改为完成状态时使用)
private List<String> eleCode; // 电子码 (日期型商品 备货状态使用)
private Date optime; // 发货/妥投/退货时间(yyyy-MM-dd HH:mm:ss)
private String approvalBizLine; // 审核业务线条
private String approvalOpinion; // 退款审核意见
private List<OrderItemOperate> orderItemOperate; // 订单项操作 (批量)
private Integer returnFreightFlag; // 是否退运费 1 退 0 不退(默认)
private String thirdOrderState1; // 第三方系统订单状态(中免扫码购:牵牛花)
private String thirdOrderState2; // 第三方系统订单状态(中免扫码购:eop)
private String refundReason; // 退款原因
private Long refundOrderId; // 退款单ID
private Integer isActual; // 是否实物退款(0:否, 1:是)
@MethodAnnotation(description = "订单ID")
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
@MethodAnnotation(description = "用户ID")
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
@MethodAnnotation(description = "售后单ID")
public Long getRepairOrderId() {
return repairOrderId;
}
public void setRepairOrderId(Long repairOrderId) {
this.repairOrderId = repairOrderId;
}
@MethodAnnotation(description = "配送单ID")
public Long getDeliveryOrderId() {
return deliveryOrderId;
}
public void setDeliveryOrderId(Long deliveryOrderId) {
this.deliveryOrderId = deliveryOrderId;
}
@MethodAnnotation(description = "第三方订单ID")
public String getInterfaceOrderId() {
return interfaceOrderId;
}
public void setInterfaceOrderId(String interfaceOrderId) {
this.interfaceOrderId = interfaceOrderId;
}
@MethodAnnotation(description = "订单状态 (4待收货 6 拒收 9已完成 11已退款 12支付后取消 16待发货 17待备货)")
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
@MethodAnnotation(description = "快递公司名称 (修改为发货状态时使用)")
public String getExpressName() {
return expressName;
}
public void setExpressName(String expressName) {
this.expressName = expressName;
}
@MethodAnnotation(description = "快递公司标准编码 (修改为发货状态时使用)")
public String getExpressCode() {
return expressCode;
}
public void setExpressCode(String expressCode) {
this.expressCode = expressCode;
}
@MethodAnnotation(description = "快递公司单号 (修改为发货状态时使用)")
public String getExpressNo() {
return expressNo;
}
public void setExpressNo(String expressNo) {
this.expressNo = expressNo;
}
@MethodAnnotation(description = "快递配送运费金额 (修改为发货状态时使用)")
public BigDecimal getExpressFreightAmount() {
return expressFreightAmount;
}
public void setExpressFreightAmount(BigDecimal expressFreightAmount) {
this.expressFreightAmount = expressFreightAmount;
}
@MethodAnnotation(description = "提货码 (自提单修改为完成状态时使用)")
public String getPickupCode() {
return pickupCode;
}
public void setPickupCode(String pickupCode) {
this.pickupCode = pickupCode;
}
@MethodAnnotation(description = "电子码 (日期型商品 备货状态使用)")
public List<String> getEleCode() {
return eleCode;
}
public void setEleCode(List<String> eleCode) {
this.eleCode = eleCode;
}
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@MethodAnnotation(description = "操作时间 (yyyy-MM-dd HH:mm:ss)")
public Date getOptime() {
return optime;
}
public void setOptime(Date optime) {
this.optime = optime;
}
@MethodAnnotation(description = "审核业务线条")
public String getApprovalBizLine() {
return approvalBizLine;
}
public void setApprovalBizLine(String approvalBizLine) {
this.approvalBizLine = approvalBizLine;
}
@MethodAnnotation(description = "退款审核意见")
public String getApprovalOpinion() {
return approvalOpinion;
}
public void setApprovalOpinion(String approvalOpinion) {
this.approvalOpinion = approvalOpinion;
}
@MethodAnnotation(description = "订单项操作")
public List<OrderItemOperate> getOrderItemOperate() {
return orderItemOperate;
}
public void setOrderItemOperate(List<OrderItemOperate> orderItemOperate) {
this.orderItemOperate = orderItemOperate;
}
@MethodAnnotation(description = "是否退运费 1 退 0 不退(默认)")
public Integer getReturnFreightFlag() {
return returnFreightFlag;
}
public void setReturnFreightFlag(Integer returnFreightFlag) {
this.returnFreightFlag = returnFreightFlag;
}
@MethodAnnotation(description = "第三方系统订单状态:牵牛花订单状态")
public String getThirdOrderState1() {
return thirdOrderState1;
}
public void setThirdOrderState1(String thirdOrderState1) {
this.thirdOrderState1 = thirdOrderState1;
}
@MethodAnnotation(description = "第三方系统订单状态:eop订单状态")
public String getThirdOrderState2() {
return thirdOrderState2;
}
public void setThirdOrderState2(String thirdOrderState2) {
this.thirdOrderState2 = thirdOrderState2;
}
@MethodAnnotation(description = "退款原因")
public String getRefundReason() {
return refundReason;
}
public void setRefundReason(String refundReason) {
this.refundReason = refundReason;
}
public Long getRefundOrderId() {
return refundOrderId;
}
public void setRefundOrderId(Long refundOrderId) {
this.refundOrderId = refundOrderId;
}
public Integer getIsActual() {
return isActual;
}
public void setIsActual(Integer isActual) {
this.isActual = isActual;
}
public static class OrderItemOperate{
private Long orderItemId; // 订单项ID
private Long skuId; // 商品Id
private Integer number; // 商品数量
private BigDecimal thirdPoints; // 分摊的thirdPoints(大会员积分需要从大会员接口获取,走埋点取,内部辅助使用)
private String storeOuCode; // 店铺编码
private String refundReason; // 退款原因
private String refundContactPhone; // 退款联系电话
public Long getOrderItemId() {
return orderItemId;
}
public void setOrderItemId(Long orderItemId) {
this.orderItemId = orderItemId;
}
public Long getSkuId() {
return skuId;
}
public void setSkuId(Long skuId) {
this.skuId = skuId;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public BigDecimal getThirdPoints() {
return thirdPoints;
}
public void setThirdPoints(BigDecimal thirdPoints) {
this.thirdPoints = thirdPoints;
}
public String getStoreOuCode() {
return storeOuCode;
}
public void setStoreOuCode(String storeOuCode) {
this.storeOuCode = storeOuCode;
}
public String getRefundReason() {
return refundReason;
}
public void setRefundReason(String refundReason) {
this.refundReason = refundReason;
}
public String getRefundContactPhone() {
return refundContactPhone;
}
public void setRefundContactPhone(String refundContactPhone) {
this.refundContactPhone = refundContactPhone;
}
}
}
}
四、避免过多使用内部类
尽管内部类在Java中是一种强大的工具,可以提供封装性、代码组织性和灵活性,但在某些情况下,使用内部类可能不是最佳选择。以下是一些建议,以帮助你在Java中避免不必要地使用内部类:
-
保持简单性:如果你的类结构变得复杂,并且开始过度依赖内部类,那么考虑是否可以通过简化设计来避免使用内部类。例如,你可以将内部类的功能移动到外部类中,或者通过接口和委托来解耦代码。
-
避免隐藏逻辑:内部类可能会隐藏一些重要的逻辑,使得其他开发者难以理解和维护代码。如果内部类的主要作用是封装某个特定逻辑,而该逻辑对于外部类或其他开发者来说很重要,那么最好将该逻辑提取到单独的外部类中。
-
考虑性能开销:内部类对象会持有对外部类对象的隐式引用,这可能导致额外的内存消耗。如果你的应用程序对性能有严格要求,并且你发现内部类导致了不必要的性能开销,那么可能需要重新考虑你的设计。
-
避免命名冲突:内部类和外部类或其他内部类之间可能存在命名冲突。为了避免这种情况,你可以使用更具描述性的类名,或者将内部类移动到单独的包中。然而,如果这样做导致代码结构变得复杂,那么可能需要重新考虑是否应该使用内部类。
-
替代方案:有时候,你可以使用其他Java特性来替代内部类。例如,你可以使用接口和匿名类来实现回调机制;使用静态方法或工具类来提供实用功能;使用组合(has-a关系)而不是继承(is-a关系)来组织类之间的关系。
-
文档和注释:如果你决定使用内部类,确保为你的代码提供充分的文档和注释。解释内部类的目的、用法和与外部类之间的关系,以帮助其他开发者理解你的代码。
总之,虽然内部类在某些情况下非常有用,但在其他情况下可能会增加代码的复杂性和维护成本。因此,在决定是否使用内部类时,请权衡其优缺点,并根据具体需求做出合理的选择。