Java sonarlint正在强制将最后一个类的常量声明为受保护

Java sonarlint正在强制将最后一个类的常量声明为受保护,java,sonarlint,Java,Sonarlint,我有一个带有私有构造函数的最后一个类: public final class Constants { public static final Date DEFAULT_DATE; static { // some code that creates localDate DEFAULT_DATE = localDate.toDate(); } private Constants() { } } Sonarint发出警告: Make DEFAUL

我有一个带有私有构造函数的最后一个类:

public final class Constants {
   public static final Date DEFAULT_DATE;

   static {
    // some code that creates localDate
    DEFAULT_DATE = localDate.toDate();
   }

   private Constants() {
   }
}
Sonarint发出警告:

 Make DEFAULT_DATE protected
 reason: Mutable fields should not be "public static"
声明它受保护是没有意义的。该类被声明为final-因此不可能继承。其次,我在其他类中使用DEFAULT_DATE,所以它必须是公共的

此外,构造函数被声明为私有的,因此不能创建任何对象


为什么sonarlint强制将默认日期设置为受保护?

这是因为DATE类是可变的,因此如果任何对象获得对Constants对象的引用,它们可以在您不知道的情况下更改dates值。最好将其设置为私有,并提供一个返回值副本的getter。

这是因为Date类是可变的,因此如果任何对象获得对Constants对象的引用,它们可以在您不知道的情况下更改dates值。最好将其设置为私有,并提供一个getter来返回值的副本。

我已经在评论中提到过。我重申这些观点,并在下文全面补充几点新观点

  • 拥有公共日期类型引用并将其视为常量(通过使用最终静态关键字声明)是一种糟糕的设计,因为它不是常量(日期是可变的)
  • 使用
    final
    关键字可防止重新分配,即不能再次使用
    =
    分配运算符。但是
    final
    关键字不阻止
    ,点运算符。使用点运算符可以修改日期对象的状态。
    常量。默认日期。设置时间(204587433443L)
    将修改假定的常量日期
  • 解决方案1:您可以将DEFAULT_DATE设置为private,并可以创建一个getter方法,当调用它时,您可以创建一个新的DATE对象,复制DEFAULT_DATE的状态并返回相同的值。这样,即使进行了任何修改,它也将位于复制的对象上,而原始对象将保持原样。对于另一次读取,将返回原始对象的新副本
  • 更好的解决方案2:将日期的长值保持为常量。让代码的调用者使用常量long值创建日期对象。(您还可以在代码中的某个位置添加实用程序方法,如果您有实用程序类,则可以将long作为输入参数,并在创建与输入long值对应的日期对象后返回日期对象。)

  • 您正在执行静态分析工具,这意味着您拥有代码。即使是它的遗留代码,也要重构它。如果它不是由您控制的部分,您可以请求处理代码的团队对其进行重构。如果它是某个第三方库的一部分,那么您可能可以向它们发送邮件并等待它们的响应,并且如果库所有者不打算更正此问题,那么您可能应该使用另一个库,因为当前的库可能有一些类似的其他问题

    我已经在评论中提到了。我重申这些观点,并在下文全面补充几点新观点

  • 拥有公共日期类型引用并将其视为常量(通过使用最终静态关键字声明)是一种糟糕的设计,因为它不是常量(日期是可变的)
  • 使用
    final
    关键字可防止重新分配,即不能再次使用
    =
    分配运算符。但是
    final
    关键字不阻止
    ,点运算符。使用点运算符可以修改日期对象的状态。
    常量。默认日期。设置时间(204587433443L)
    将修改假定的常量日期
  • 解决方案1:您可以将DEFAULT_DATE设置为private,并可以创建一个getter方法,当调用它时,您可以创建一个新的DATE对象,复制DEFAULT_DATE的状态并返回相同的值。这样,即使进行了任何修改,它也将位于复制的对象上,而原始对象将保持原样。对于另一次读取,将返回原始对象的新副本
  • 更好的解决方案2:将日期的长值保持为常量。让代码的调用者使用常量long值创建日期对象。(您还可以在代码中的某个位置添加实用程序方法,如果您有实用程序类,则可以将long作为输入参数,并在创建与输入long值对应的日期对象后返回日期对象。)

  • 您正在执行静态分析工具,这意味着您拥有代码。即使是它的遗留代码,也要重构它。如果它不是由您控制的部分,您可以请求处理代码的团队对其进行重构。如果它是某个第三方库的一部分,那么您可能可以向它们发送邮件并等待它们的响应,并且如果库所有者不打算更正此问题,那么您可能应该使用另一个库,因为当前的库可能有一些类似的其他问题

    回答我自己的问题:

    正如其他人所解释的那样,
    java.util.Date
    是一个可变的,因此将其作为常量提供是一个糟糕的设计,因为它实际上不是

    @nits.kk提供了一个更好的解决方案,即“将日期的长值保持为常量”,并使用“让调用者将长值转换为日期对象”

    public static final long DEFAULT_DATE = <long value representing the required date>;
    

    这样我就保留了预期的日期对象,静态检查器将不再发出警告/错误。

    回答我自己的问题:

    正如其他人所解释的那样,
    java.util.Date
    是一个可变的,因此将其作为常量提供是一个糟糕的设计,因为它实际上不是

    @nits.kk提供了一个更好的解决方案,即“将日期的长值保持为常量”,并使用“让调用者将长值转换为日期对象”

    public static final long DEFAULT_DATE = <long value representing the required date>;
    

    这样,我保留了预期的日期对象,静态检查器将不再发出警告/错误。

    调用方仍然可以修改副本的值。如何强制调用方使用常量?此外,还有一个旧代码将此常量称为Constants.DEFAULT_DATE。添加getter需要更改