1)
if(obj.equals(obj))
It's true that the default equals
implementation just uses ==
to check if the two objects (actually, the two references) are actually referring to the same object in memory, but it's nonetheless a call to an instance method, which is bound to fail with a NullPointerException
if it's called over a null
.
if(null==null)
instead doesn't give any problem, since you are not calling any instance method, you are just comparing addresses.
2) void
is just a keyword used to mark a function returning nothing1; it doesn't make any sense to try to return it. null
, instead, marks an object reference as pointing to nothing, that's an entirely different concept.
3) In C++ there's no default "equals" method, and the whole object model is based on value types (in Java, instead, you normally work with references to objects), so it's difficult to make a precise comparison.2
In C++ an object (or a reference) is guaranteed to be a "valid" object (=there's space allocated for it and a constructor has run), so there's no possibility of getting an hypothetical equivalent of NullPointerException
when calling an instance method over an object.
On the other hand, it's entirely possible to have a pointer that is NULL
, and in such case you go into undefined behavior (usually a crash) if you try to dereference it in some way (e.g. via *
or ->
)3.
As for the equality checks: the ==
operator for objects is not implemented by default, so comparing objects for equality makes sense only if the implementor of the class actually wrote an overload for operator==
; as for pointers, the ==
operator is provided by the language itself (and cannot be overridden), and it actually compares the two addresses.
- In contrast to C and C++, where
void
is considered a type (in particular, "an incomplete type that cannot be completed"), in Java it's not, although in some respects it can be considered as such.
- In C there are no classes or methods period - it's not an OO language; still, most of the discussion that follows applies to
struct
s and accessing their fields.
- Although... if an instance method isn't
virtual
and doesn't use any field of the object (=the this
pointer isn't dereferenced in any way), in most implementations you may get away with calling an instance method on a NULL
pointer. Also, by "formally dereferencing" a pointer you can get away with creating a "null reference", that will probably cause trouble when it's used. But in both cases it's still undefined behavior - i.e., it's not correct, although no preventive checks are normally performed, favoring performance over strict rules enforcing.