【问题标题】:Final Keyword in Constant utility class常量实用程序类中的最终关键字
【发布时间】:2011-05-26 05:39:30
【问题描述】:

当使用 final 关键字和常量实用程序类时,性能和/或任何其他好处是否存在差异。 [该类仅包含静态最终字段和私有构造函数以避免创建对象]

public class ActionConstants {
    private ActionConstants()  // Prevents instantiation
    {   }

    public static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
    public static final String VALIDPHONENUMBER = "\\d{10}";
    ...
    ...
}

唯一的区别是类是最终的

 public final class ActionConstants {
    private ActionConstants()  // Prevents instantiation
    {   }

    public static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
    public static final String VALIDPHONENUMBER = "\\d{10}";
    ...
    ...
}

我想知道,使用 final 有什么好处吗?为常量定义类的正确方法是什么。

【问题讨论】:

    标签: java performance class constants final


    【解决方案1】:

    没有任何好处。它不会改变您的 static final 属性。

    当一个类成为最终类时,编译器可以利用这一点来覆盖可覆盖的方法(静态方法不能被覆盖,充其量它们会将那些隐藏在继承的类中)。

    由于类是最终类,编译器知道它的任何方法都不能被覆盖。因此,它可以计算不需要生成多态性代码的情况(即,代码在运行时根据对象实例找到覆盖方法的正确“版本”)。因此,可以进行优化。

    如果你想让一个类真正独一无二,你可以使用这样的东西:

    public enum ActionConstants {
    
        INSTANCE;
    
        public static final int cte1 = 33;
        public static final int cte2 = 34;
    
    }
    

    如果您对类实例根本不感兴趣,只需将所有常量放在接口中即可。

    【讨论】:

    • 不确定您是否需要INSTANCE。我会有一个没有实例的枚举。
    • 通常“接口应该只用于定义类型。它们不应该用于导出常量。”
    • @Peter Lawrey 你需要为枚举提供至少一个值,我称之为我的 INSTANCE,但它可能是anyhting...
    • @JVerstry,哪里说你至少需要一个?您是否尝试过删除 INSTANCE 并仅放置 ;
    • @JVersty,有些人会认为没有实例的枚举是 hack。 ;)
    【解决方案2】:

    如果您正在寻找改进的性能,最好预先编译您的模式,例如

    public static final Pattern VALIDFIRSTLASTNAME = Pattern.compile("[A-Za-z0-9.\\s]+");    
    public static final Pattern VALIDPHONENUMBER = Pattern.compile("\\d{10}");
    

    与使用正则表达式相比,是否使用 final 是非常小的。

    【讨论】:

    【解决方案3】:

    没有真正的好处,但它确实强化了您的期望,即没有任何东西可以扩展您的课程。从长远来看,这可能会更容易,例如,在您的代码中搜索常量的所有用途,因为它们将被保证是 XXX.abc 而不是 YYY.abc,其中 YYY 扩展了 XXX。

    【讨论】:

      【解决方案4】:

      您应该避免使用“常量类”。这意味着糟糕的设计。将常量放在使用它们的类中。也避免使用公共常量。这应该是例外,而不是正常做法。

      【讨论】:

      • 这通常是更好的做法,但并非总是。在某些情况下,有些常量并不真正属于使用它们的任何一个类。
      • 您能举个例子吗?
      • 想想数学内容,例如。你不会想在使用它们的每个地方都定义它们。
      • 我提到该规则有一些例外。但正则表达式模式并非如此。
      【解决方案5】:

      将类用于常量是不常见的。在大多数情况下,使用接口。 ActionConstants.VALIDFIRSTLASTNAME 可以访问此地址:

      public interface ActionConstants {
        static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
        static final String VALIDPHONENUMBER = "\\d{10}";
        ...
      }
      

      从 Java 5 开始,您还可以使用枚举。枚举可以有成员或扩展功能。

      第二个示例使用一个简单的成员(如果您有不同的常量类型,这里使用通用方法,否则您也可以使用String 成员):

      public enum ActionConstants {
      
        FIRSTLASTNAME("[A-Za-z0-9.\\s]+"),
        PHONENUMBER("\\d{10}");
      
        private final Object value;
      
        private ActionConstants(Object value) {
          this.value= value;
        }
      
        @SuppressWarnings("unchecked")
        public <T> T getValue() {
          return (T)value;
        }
      
      }
      
      String value = ActionConstants.FIRSTLASTNAME.getValue();
      

      最后一个示例在所有常量都属于同一类型时使用扩展功能。 你可以像ActionConstants.PHONENUMBER.isValid("0800123456")一样使用它:

      public enum ActionConstants {
      
        FIRSTLASTNAME("[A-Za-z0-9.\\s]+"),
        PHONENUMBER("\\d{10}");
      
        private final Pattern pattern;
      
        private ActionConstants(String pattern) {
          this.pattern = Pattern.compile(pattern);
        }
      
        public void isValid(String value) {
          return pattern.matcher(value).matches();
        }
      
      }
      

      两个版本都允许使用静态导入。

      【讨论】:

      • 看起来对这个答案投了反对票,这种方法有什么问题吗。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      • 2022-10-07
      • 1970-01-01
      • 2012-10-11
      • 2014-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多