【问题标题】:How am I able to call a method on a null object?如何调用空对象的方法?
【发布时间】:2012-01-25 00:06:44
【问题描述】:
public class JavaPuzzler {

    public static void main(String[] args) {
    JavaPuzzler javaPuzzler = null;
    System.out.println(javaPuzzler.get());
    }

    private static String get(){
        return "i am a java puzzler";
    }
}

你可能认为它应该抛出 NullPointerException,因为 main 方法调用了 已初始化的局部变量的 get() 方法 为 null,并且您不能在 null 上调用方法。

但是如果你运行这个程序,你会看到它打印出“i am a javauzzler”。

谁能给我答案。 提前致谢。

【问题讨论】:

  • 我认为在您的打印语句中它的 JavaPuzzler.get() 带有大写 J
  • @Nikunj 的问题是绝对正确的,没有任何错误。
  • @NikunjChauhan,不,代码是正确的,将按照发布的方式运行......小写“j”等等。显然你和你的两个支持者没有先尝试:)
  • @Paul:是的..检查我的答案!

标签: java core


【解决方案1】:

在上面的代码中,您将 get() 函数作为静态函数。静态函数和数据成员不属于任何对象。他们属于阶级。您可以使用类对象调用静态函数,但这不是一个好方法,因为它会消耗额外的内存。

由于是静态的,JavaPuzzler.get());会给你输出而不是空指针异常。

如果 get() 方法是非静态的,它会给出空指针异常。

【讨论】:

    【解决方案2】:

    编译器自动将实例调用更改为类调用。如果你有反编译器,你可以观察生成的字节码的变化:

    ...
     public static main([Ljava/lang/String;)V
       L0
        LINENUMBER 8 L0
        ACONST_NULL
        ASTORE 1
       L1
        LINENUMBER 9 L1
        GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
        INVOKESTATIC JavaPuzzler.get()Ljava/lang/String;
        INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
       L2
        LINENUMBER 11 L2
        RETURN
       L3
        LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
        LOCALVARIABLE javaPuzzler LJavaPuzzler; L1 L3 1
        MAXSTACK = 2
        MAXLOCALS = 2
    ...
    

    【讨论】:

      【解决方案3】:

      就像每个人在这里提到的那样,它之所以有效,是因为get() 是一个静态方法。以下是您可以考虑的一种方式:

      当您在 Java 中定义一个类时,您实际上所做的是定义一个对象将保存的数据,以及一组对该数据进行操作的方法。现在,虽然您可以拥有成千上万个对象,但为每个对象拥有所有方法的副本是没有意义的。发生的情况是该类存储您定义的方法,并在您调用该方法的对象的范围中执行它们。如果您尝试在未初始化的对象上调用这些方法,则该对象仍然存在并且该方法仍然存在,但是它没有有效的工作范围,从而为您提供NullPointerException

      此规则的例外是静态方法,它们是不需要范围的方法 - 它们不引用特定于对象的数据。这就是为什么无论对象是否初始化,它们都可以运行。

      请记住,对象没有其方法的副本……这些方法只是在对象数据的范围内调用。所以你仍然可以访问空(未初始化)对象的方法,但非静态方法没有数据可以处理。

      【讨论】:

        【解决方案4】:

        这是因为该方法是静态的,尽管您引用了一个实例,但该实例不是必需的。 Java 语言规范在section 8.4.3.2 中解释了原因:

        声明为静态的方法称为类方法。一类 方法总是在不引用特定对象的情况下被调用。

        这意味着 javaPuzzler 实例是否为 null 无关紧要 - 方法“属于”类,而不是实例。

        【讨论】:

          【解决方案5】:

          如果我们尝试使用 NULL 对象调用方法,只要该方法不是静态的,它就会抛出 NullPointerException

          如果方法是静态的,它将运行。

          阅读HERE以获取更多参考

          【讨论】:

            【解决方案6】:

            你正在调用一个静态方法,你不需要实例来调用它,这就是它起作用的原因。

            【讨论】:

              【解决方案7】:

              get 方法是静态的,这意味着在该调用中将忽略 javaPuzzler 中的实际引用,只使用变量的类型。

              【讨论】:

                【解决方案8】:

                您的方法是静态的。所以只能静态调用。

                因此,即使您将其作为 javaPuzzler.get(),实际调用将是 JavaPuzzler.get() 并因此打印!!

                【讨论】:

                  【解决方案9】:

                  在您的代码示例中,get() 是一个静态成员,属于类,而不是实例。调用该方法不需要实例。

                  public static String get() // belongs globally to class, no instance required
                  public String get() // belongs to instance
                  

                  【讨论】:

                  • 这似乎有点错误,它在(尽管null)实例变量上调用静态方法。不过很有趣。
                  • @Andrew Marshall:如果你在eclipse中尝试代码,它会自动从instance.call()改为Class.call()
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多