Java受限长度字符串类实现及内存优化问题咨询
问题与优化方案
问题背景
需要实现一个类似String的自定义类型(Java无法继承String),用于约束联系人姓名:
- 名:长度不超过10字符,不可为空
- 姓:长度不超过15字符,不可为空
原代码试图将LimitedString的约束字段(描述、长度限制、是否可空)设为static final以减少集合中联系人的内存占用,但该方案无法正常工作——静态字段属于类级别,所有实例共享,会导致不同约束的实例(如名和姓)互相覆盖约束规则,校验逻辑完全失效。
核心问题分析
- 静态字段滥用:
descriptor、minimumLength、maximumLength、nullable被定义为static final,所有LimitedString实例共用这些值。创建firstName和lastName实例时,后创建的实例会覆盖静态字段值,导致校验规则混乱。 - 构造方法错误:无初始值的构造方法调用
setValue(value)时,value未初始化,直接触发空指针或非法参数异常。 - 代码规范问题:
ToString()不符合Java驼峰命名规范(应为toString());String.format占位符错误(@s应为%s)。
优化方案
方案思路
将约束规则封装为独立的配置类,让相同约束的LimitedString实例共享该配置对象——既保证每个实例有正确的约束规则,又能减少内存占用(相同约束的实例共用一个配置,无需重复存储约束字段)。同时修复代码中的错误,完善校验逻辑。
修改后的代码
1. 约束配置类 StringConstraint
package Models; public class StringConstraint { private final String descriptor; private final int minimumLength; private final int maximumLength; private final boolean nullable; public StringConstraint(String descriptor, int minimumLength, int maximumLength, boolean nullable) { if (minimumLength < 0) { throw new IllegalArgumentException("最小长度不能小于0"); } if (minimumLength > maximumLength) { throw new IllegalArgumentException("最小长度不能大于最大长度"); } this.descriptor = descriptor; this.minimumLength = minimumLength; this.maximumLength = maximumLength; this.nullable = nullable; } // Getter方法 public String getDescriptor() { return descriptor; } public int getMinimumLength() { return minimumLength; } public int getMaximumLength() { return maximumLength; } public boolean isNullable() { return nullable; } }
2. 优化后的 LimitedString 类
package Models; public class LimitedString { private String value; private final StringConstraint constraint; // 带初始值的构造方法 public LimitedString(String value, StringConstraint constraint) { this.constraint = constraint; setValue(value); } // 空构造方法(用于后续设置值) public LimitedString(StringConstraint constraint) { this.constraint = constraint; } @Override public String toString() { return value; } public String getValue() { return value; } public void setValue(String value) { // 校验空值 if (value == null && !constraint.isNullable()) { throw new IllegalArgumentException(constraint.getDescriptor() + " 不能为空"); } // 校验长度 if (value != null) { int length = value.length(); if (length < constraint.getMinimumLength() || length > constraint.getMaximumLength()) { throw new IllegalArgumentException(String.format( "%s 长度必须在 %d 到 %d 字符之间", constraint.getDescriptor(), constraint.getMinimumLength(), constraint.getMaximumLength() )); } } this.value = value; } public StringConstraint getConstraint() { return constraint; } }
3. 优化后的 Contact 类
package Models; public class Contact { // 定义全局共享的约束实例,所有Contact的firstName/lastName共用 private static final StringConstraint FIRST_NAME_CONSTRAINT = new StringConstraint("名", 1, 10, false); private static final StringConstraint LAST_NAME_CONSTRAINT = new StringConstraint("姓", 1, 15, false); private final LimitedString firstName; private final LimitedString lastName; // 构造方法直接初始化值 public Contact(String firstName, String lastName) { this.firstName = new LimitedString(firstName, FIRST_NAME_CONSTRAINT); this.lastName = new LimitedString(lastName, LAST_NAME_CONSTRAINT); } // Getter方法(若不需要修改姓名,可去掉Setter,让Contact不可变) public String getFirstName() { return firstName.getValue(); } public String getLastName() { return lastName.getValue(); } // 若需要支持修改姓名,添加Setter public void setFirstName(String firstName) { this.firstName.setValue(firstName); } public void setLastName(String lastName) { this.lastName.setValue(lastName); } }
优化说明
- 内存优化:通过
StringConstraint共享约束规则,所有Contact的firstName共用同一个FIRST_NAME_CONSTRAINT实例,lastName同理,避免每个LimitedString实例重复存储约束字段,有效减少内存占用。 - 逻辑正确性:每个
LimitedString实例持有独立的约束引用,不同类型的字段(名/姓)不会互相覆盖规则,校验逻辑正常工作。 - 代码规范:修复了
toString()命名、占位符错误等问题,完善了异常提示信息。 - 可扩展性:新增约束类型时,只需创建新的
StringConstraint实例,无需修改LimitedString类。
内容的提问来源于stack exchange,提问作者Charles Hilton
相关产品推荐
相关产品推荐

