Java中的“this”可以为空吗?
Posted
技术标签:
【中文标题】Java中的“this”可以为空吗?【英文标题】:Can "this" ever be null in Java? 【发布时间】:2011-04-16 21:56:41 【问题描述】:在类方法中看到这一行,我的第一反应是嘲笑编写它的开发人员。但后来,我想我应该首先确保我是对的。
public void dataViewActivated(DataViewEvent e)
if (this != null)
// Do some work
那条线会评估为假吗?
【问题讨论】:
总是先嘲讽,后质疑。道歉比重新抓住一个在硫磺火中摧毁某人的黄金机会更容易。 +1 表示“硫磺乱舞”。 你知道有什么好笑的吗?由于编译器错误,这可能在 C# 中发生! @Blindy 会给代码示例 +1。 在 C# 中它可以为空。在某些边缘情况下。我也有同样的冲动:嘲笑这个傻瓜,但后来我才冷静下来。看看这里:***.com/questions/2464097/… 【参考方案1】:不,它不能。如果您使用的是this
,那么您就在实例中,所以this
不为空。
JLS 说:
当用作主要表达式时,关键字 this 表示一个值,该值是对调用实例方法的对象(第 15.12 节)或正在构造的对象的引用。
如果您从对象调用方法,则该对象存在,或者您之前将有一个 NullPointerException
(或者它是一个静态方法,但您不能在其中使用 this
)。
资源:
JLS -this
keyword
【讨论】:
我对 Java 了解不多,但在 C++ 中,实例方法的this
可能为 NULL。所以我不太相信这是 Java 的充分理由。
当发现foo
为null
时,会抛出类似foo.bar()
的空指针异常。它确实发生在进入方法之前,但真正的故事是没有方法可以尝试调用。
@KennyTM:在 Java 中就足够了。如果您使用 this
关键字并且它可以编译,那么当您观察它时它不为空。但正如其他人所说,在尝试调用该方法时不会阻止 NPE,例如但这完全超出了您作为方法的控制范围,并且该方法中的 null 检查不会改变任何内容。
@Kenny:不是没有undefined behavior,不过如果你知道你的实现细节,你可以使用它。
我不会订阅这个明确的答案,即使它完全有道理。我有一个 android 应用程序的崩溃报告,其中 this == null 在变量从另一个线程被空化后立即调用实例方法。即使变量为空,实际调用也会通过,并且在尝试读取实例成员时崩溃:)【参考方案2】:
这就像问自己“我还活着吗?” this
永远不能为空
【讨论】:
我我还活着?!天哪,我不知道了 你说的好像this != null
是不言而喻的。它不是 - 例如,在 C++ 中,this
很可能是 NULL
,用于非虚拟方法。
@nikie 在某种意义上,这是不言而喻的。即使在 C++ 中,任何发生这种情况的程序都有未定义的行为。 GCC 上的虚函数也可能发生这种情况:ideone.com/W7RmU。
@JohannesSchaub-litb 带有 null ref 的 c++ 程序的行为未定义是不正确的。只要您不取消引用它,它就会被定义【参考方案3】:
No never,关键字'this'本身代表该类在该类范围内的当前活动实例(对象),您可以使用它访问其所有字段和成员(包括构造函数) ) 及其父类的可见部分。
而且,更有趣的是,尝试设置它:
this = null;
考虑一下?怎么可能,岂不是像砍掉你坐的树枝一样。由于关键字“this”在类的范围内可用,因此只要你说 this = null;在类中的任何位置,那么您基本上是在要求 JVM 在某些操作中间释放分配给该对象的内存,这是 JVM 不允许发生的,因为它需要在完成该操作后安全返回。
此外,尝试this = null;
将导致编译器错误。原因很简单,Java(或任何语言)中的关键字永远不能被赋值,即关键字永远不能是赋值操作的左值。
其他例子,你不能说:
true = new Boolean(true);
true = false;
【讨论】:
我发现这个是因为我想看看我是否可以使用this = null
。我的实例在 android 中,我想删除一个视图并将处理视图的对象设置为 null。然后我想使用remove()
方法,它会删除实际视图,然后处理程序对象将变得无用,所以我想将其设为空。
不确定我是否同意您的说法。 (至少中间部分;左值部分很好......虽然我很确定实际上有一些破碎的语言允许你分配例如 true = false (甚至我不会称之为破碎的语言也可能允许它与反射或类似的诡计))。无论如何,如果我有一些对象 foo 并且我要做(忽略它是非法的)foo.this = null,foo 仍将指向内存,因此 JVM 不会垃圾收集它。
@Foon 很好,这个问题正是关于 Java 语言的,此外,我还没有遇到任何允许设置 this=null 的语言。也就是说,如果确实存在这样的语言,那么我非常怀疑这些语言中的“this”是否具有相同的上下文和意识形态。【参考方案4】:
如果您使用-target 1.3
或更早版本进行编译,则外部 this
可能是null
。或者至少它曾经...
【讨论】:
我想通过反射我们可以将外部 this 设置为 null。当某人在引用Outer.this.member
时遇到空指针异常时,这可能是一个愚人节玩笑
@irreputable 可能对反序列化感兴趣以选择外部/内部对象实例化的顺序
@SamGinrich 哦,这是一个有趣的观点,似乎没有其他答案可以解决。在 Java 序列化中,至少,在反序列化期间初始化的顺序字段由流确定。 OTOH,如果这引起了问题,那么您有更大的问题。
@irreputable Actual 在替换具有硬尺寸限制的标准 ObjectInpput/OutputStream 时出现了订单问题。事实证明,反射可以暂时创建一个带有 Outer.this == null 的内部对象“独立”,并稍后绑定 Outer 对象(如果不这样做,行为肯定是未定义的!)【参考方案5】:
没有。要调用类实例的方法,该实例必须存在。该实例作为参数隐式传递给方法,由this
引用。如果this
是null
,那么就没有实例可以调用其方法。
【讨论】:
【参考方案6】:语言强制执行它是不够的。 VM 需要强制执行它。除非 VM 强制执行它,否则您可以编写一个编译器,在调用用 Java 编写的方法之前不强制执行 null 检查。 实例方法调用的操作码包括将 this ref 加载到堆栈上,请参阅:http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787。用 this 代替 null ref 确实会导致测试为假
【讨论】:
【参考方案7】:普通的this
在真正的Java 代码中永远不可能是null
1,而您的示例使用普通的this
。有关详细信息,请参阅其他其他答案。
合格的this
应该永远不会是null
,但有可能打破这一点。考虑以下几点:
public class Outer
public Outer()
public class Inner
public Inner()
public String toString()
return "outer is " + Outer.this; // Qualified this!!
当我们要创建Inner
的实例时,我们需要这样做:
public static void main(String[] args)
Outer outer = new Outer();
Inner inner = outer.new Inner();
System.out.println(inner);
outer = null;
inner = outer.new Inner(); // FAIL ... throws an NPE
输出是:
outer is Outer@2a139a55
Exception in thread "main" java.lang.NullPointerException
at Outer.main(Outer.java:19)
表明我们尝试创建带有 null
引用的 Inner
到其 Outer
的尝试失败了。
事实上,如果你坚持“纯 Java”信封,你就无法打破它。
但是,每个Inner
实例都有一个隐藏的final
合成字段(称为"this$0"
),其中包含对Outer
的引用。如果您真的很棘手,可以使用“非纯”的方式将null
分配给该字段。
Unsafe
来执行此操作。
您可以使用本机代码(例如 JNI)来执行此操作。
您可以使用反射来做到这一点。
无论您采用哪种方式,最终结果都是Outer.this
表达式的计算结果为null
2。
简而言之,合格的this
有可能为null
。但如果您的程序遵循“纯 Java”规则,则不可能。
1 - 我对诸如手动“编写”字节码并将它们作为真正的 Java 传递、使用 BCEL 或类似方法调整字节码、或跳入本机代码并使用保存的寄存器等技巧打折扣。 IMO,那不是 Java。假设,这样的事情也可能由于 JVM 错误而发生......但我不记得每一次看到的错误报告。
2 - 实际上,JLS 并没有说明行为将是什么,它可能取决于实现......除其他外。
【讨论】:
【参考方案8】:在静态类方法中,this
未定义,因为this
与实例相关联,而不是类。我相信尝试在静态上下文中使用 this
关键字会导致编译器错误。
【讨论】:
【参考方案9】:当您在 null
引用上调用方法时,Java VM 将抛出 NullPointerException
。这是规范,所以如果你的 Java VM 严格遵守规范,this
永远不会是 null
。
【讨论】:
【参考方案10】:如果方法是静态的,则没有任何this
。如果方法是虚拟的,那么this
不能为空,因为为了调用该方法,运行时需要使用this
指针来引用vtable。如果方法不是虚拟的,那么,是的,this
可能为空。
C# 和 C++ 允许使用非虚拟方法,但在 Java 中所有非静态方法都是虚拟的,因此 this
永远不会为空。
【讨论】:
【参考方案11】:tl;dr,“this”只能从非静态方法调用,我们都知道非静态方法是从某种不能为空的对象调用的。
【讨论】:
以上是关于Java中的“this”可以为空吗?的主要内容,如果未能解决你的问题,请参考以下文章