Java维护常量方式的比较——接口、常量类与枚举
一、示例
1.让类实现定义了常量的接口
public interface Constants{
int SUCCESS = 1;
int ERROR = 2;
}
2.定义常量类
public class Constants{
public static final int SUCCESS = 1;
public static final int ERROR = 2;
}
3.定义枚举
@Getter
@AllArgsConstructor
public enum ResultEnum {
SUCCESS(1),
ERROR(2);
private int value;
}
二、比较
1.在接口中定义常量是不被建议的
如果某个实现了常量接口的类后续不再需要常量了,然而由于序列化的兼容原因不得不保持改冗余的实现(因为不保持实现的话会导致反序列化异常),而且由于接口中的常量并非final,也就是说继承了实现该接口的所有子类也同样被污染。
2.枚举和常量不是一个维度的东西,枚举是对象,常量是字段
常量能做的,枚举都能做,枚举能做的常量不一定能做
每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的
而常量类中通常也使用 public static final 修饰常量
3.入参约束:对于常量很难约束调用者按你的意图传参,但枚举不仅可以约束入参,还能很好的提示调用者
4.switch语句支持枚举型,当switch使用int、String类型时,由于值的不稳定性往往会有越界的现象,对于这个的处理往往只能通过if条件筛选以及default模块来处理。而使用枚举型后,在编译期间限定类型,不允许发生越界的情况
1)常量类
- 常量作为参数时,是String,int等弱类型,开发人员可以传入没有在常量接口里定义的值,这个问题无法通过编译器发现
- 由于开发人员可以直接写常量,所以不能用==对比,只能用equals对比,不能优化性能
equals是比较两个对象的内容是否相等,== 比较的是两个对象的地址是否相同
而处于不同地址的两个对象是可以相同的,所以对于常量来说,用户传入的参数是自己写的(新创建的)常量,与常量类中定义的常量显然是不同的对象,所以要比较的是内容是否相同而非地址
而对于枚举,参数接收的是枚举中定义的静态对象(即传入的就是事先存在的、枚举中的对象),即常量值地址唯一(因为其构造函数是私有的,无法通过外部构造出对象),所以只要比较地址即可
- 开发人员没有参考资料时,不可能知道某个int类型的参数到底应该赋什么内容
- 编译时,是直接把常量的值编译到类的二进制代码里,所以当常量的值进行更改之后是需要重新编译已更改原本的旧值的
2)枚举
- 构造方法默认的修饰符是privatem,故常量值地址唯一,可以用==直接对比,性能会有提高
- 编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类
三、使用场景
无规则归类的一些常量:如SUCCESS字符串、密钥串、路径等等可以放在一个常量类里面
而对于数据库中对应type、status类型字段并且是可以枚举出来的,此外比如错误码等强烈建议使用enum类型