代码之家  ›  专栏  ›  技术社区  ›  Magnus

如何防止在类的实例上调用静态方法[[副本]

  •  0
  • Magnus  · 技术社区  · 6 年前

    我有下面的类,用于控制Android应用程序中不同位置的一些调试和beta测试选项。它只包含一些标志和一些逻辑来(反)序列化JSON。

    public class DevConfiguration {
        public boolean dontSendSMS;
    
    
        public static String toJsonString(DevConfiguration devConfiguration) {
            JSONObject json = new JSONObject();
    
            if( devConfiguration != null ) {
                try {
                    json.put("dontSendSMS", devConfiguration.dontSendSMS);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
    
            return json.toString();
        }
    
    
        public static DevConfiguration fromJsonString(String jsonString) {
            if( jsonString.isEmpty() )
                return null;
    
            DevConfiguration result = new DevConfiguration();
    
            try {
                JSONObject jsonObj = new JSONObject(jsonString);
                result.dontSendSMS = jsonObj.optBoolean("dontSendSMS", false);
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
            return result;
        }
    
    }
    

    现在,在我的一个服务中,我收到一个序列化的 DevConfiguration 中的对象 Intent ,以后可能会将其传递给另一个服务:

    serviceIntent.putExtra("dev_conf", DevConfiguration.toJsonString(mDevConfiguration));
    

    我选择做 toJsonString() null 实例。但是,仍然有可能在某个地方出错,并在实例上调用静态方法—可能是 无效的 实例!

    mDevConfiguration.toJsonString(mDevConfiguration);
    

    在androidstudio中有一个Lint警告,但它仍然是一个潜在的问题 NullPointerException private

    /** Hide instance implementation **/
    private String toJsonString(Object o){ return ""; }
    

    当然,用一个

    有没有什么方法可以对实例变量“隐藏”静态方法?

    编辑

    无效的 这是完全合法的。然而,问题并非如此 “在空实例上调用静态方法时,如何防止NullPointerException?” ,但更一般 “如何防止在类的实例上调用静态方法?” .

    换句话说,如果一个人不小心试图调用实例上的静态方法,有没有什么方法可以阻止编译器编译呢?

    2 回复  |  直到 6 年前
        1
  •  3
  •   user3078523    6 年前

    对具有空值的变量调用静态方法不会引发NullPointerException。将打印以下代码 42 即使可变 i 为空。

    public class Test {
        public static void main(String... args) {
            Integer i = null;
            System.out.println(i.parseInt("42"));
        }
    }
    

    当通过变量调用静态方法时,真正重要的是变量的声明类型,而不是其值的引用类型。这与java中的静态方法不是多态的这一事实有关。


    如何防止在类的实例上调用静态方法?”

    但是在类中使用这样的静态(工厂)方法是一个非常好的习惯用法(参见示例:Joshua Bloch,Effective Java,Item 1:考虑静态工厂方法而不是构造函数)。我不会轻易放弃的。

        2
  •  0
  •   TheWanderer    6 年前

    我想有几种方法可以做到这一点:

    1. 使用Utils类:

      public class Utils {
          public static String toJsonString(DevConfiguration devConfiguration) {
              JSONObject json = new JSONObject();
      
              if( devConfiguration != null ) {
                  try {
                      json.put("dontSendSMS", devConfiguration.dontSendSMS);
                  } catch (JSONException e) {
                      e.printStackTrace();
                  }
              }
      
              return json.toString();
          }
      
      
          public static DevConfiguration fromJsonString(String jsonString) {
              if( jsonString.isEmpty() )
                  return null;
      
              DevConfiguration result = new DevConfiguration();
      
              try {
                  JSONObject jsonObj = new JSONObject(jsonString);
                  result.dontSendSMS = jsonObj.optBoolean("dontSendSMS", false);
              } catch (JSONException e) {
                  e.printStackTrace();
              }
      
              return result;
          }
      }
      

      现在你可以打电话给 Utils.method() 避免混淆。

    2. 使用Kotlin

      Kotlin实际上使得在动态接收器上调用静态方法非常困难(如果不是不可能的话)。它不会显示在方法建议中,如果手动键入,它将以红色下划线显示。它甚至可能无法编译,尽管我还没走那么远。

      Kotlin还有内置的空保护: instance?.method() . 这个 ? 方法 method() 只是不会执行如果 instance 为空。

    3. 只是不要在动态接收器上调用静态方法。如果你不小心做了,回去修理。你不应该依赖Java来解决你的语法错误。

    mDevConfiguration 总是空的,除非你在一个非常奇怪的地方初始化它。如果是这样的话,您可能需要重新组织代码。因为,同样,您不应该依赖Java来解决语法错误。另外,如果为null,它不会抛出NPE,至少在Java中是这样,因为它不需要动态接收器来运行(这在Kotlin中可能是不同的)。

    抱歉,如果上述听起来很苛刻,但我真的很难理解为什么你要这样做,而不是只是检查你的代码。

    真正地 DevConfiguration 私人:

    public class DevConfiguration {
        //...
    
        private DevConfiguration() {}
    
        //...
    }