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上调用方法。
但是如果你运行这个程序,你会看到它打印出“我是一个java puzzler”。
任何人都可以给我答案。 提前谢谢。
答案 0 :(得分:6)
在您的代码示例中,get()
是属于该类的静态成员,而不是实例。您不需要实例来调用该方法。
public static String get() // belongs globally to class, no instance required
public String get() // belongs to instance
答案 1 :(得分:4)
这是因为该方法是静态的,虽然您引用了一个实例,但实例并不是必需的。 Java语言规范在section 8.4.3.2中解释了原因:
声明为static的方法称为类方法。一类 始终在不引用特定对象的情况下调用方法。
这意味着javaPuzzler
实例为空是无关紧要的 - 方法“属于”类,而不是实例。
答案 2 :(得分:3)
get
方法是静态的,这意味着在该调用中忽略了javaPuzzler
中的实际引用,只使用了变量的类型。
答案 3 :(得分:1)
您的方法是静态的。所以它只能以静态方式调用。
所以即使你把它作为javaPuzzler.get(),实际调用将是JavaPuzzler.get(),因此打印!!
答案 4 :(得分:1)
您正在调用静态方法,您不需要实例来调用它,这就是它的工作原理。
答案 5 :(得分:1)
答案 6 :(得分:1)
像所有人在这里提到的那样,它起作用是因为get()
是一种静态方法。以下是您可以考虑的方法:
在Java中定义类时,您实际上要做的是定义对象将保存的数据,以及一组对该数据进行操作的方法。现在,虽然您可以拥有成千上万个对象,但是为每个对象提供所有方法的副本是没有意义的。会发生的是,类存储您定义的方法,并在您调用方法的对象的范围中执行它们。如果您尝试在未初始化的对象上调用这些方法,则该对象仍然存在,并且该方法仍然存在,但它无法使用范围,从而为您提供NullPointerException
。
此规则的例外是静态方法,它们是不需要范围的方法 - 它们不引用特定于对象的数据。这就是为什么它们可以运行而不管对象是否被初始化。
请记住,对象没有方法的副本......这些方法只是在对象数据的范围内调用。所以你仍然可以访问null(未初始化的)对象的方法,但是非静态方法没有数据可以处理。
答案 7 :(得分:0)
编译器自动将实例调用更改为类调用。如果你有一个反编译器,你可以观察生成的字节码的变化:
...
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
...
答案 8 :(得分:0)
在上面的代码中,你给了get()函数static。静态函数和数据成员不属于任何对象。他们属于这个班级。您可以使用类的对象调用静态函数,但这不是一个好方法,因为它会消耗额外的内存。
自static,JavaPuzzler.get());将为您提供输出而不是空指针异常。
如果get()方法是非静态的,它会给出空指针异常。