简体   繁体   中英

Comparison of two null objects from two different types

public void m1(Integer f) {
    ...
}

public void m1(Float f) {
    ...
}

public void main() {
    m1(null); // error: the method m1(Integer) is ambiguous for the type Main
    m1((Integer) null); // success
}

Given the above example, we can admit in some ways that null is typed. So why do the following lines print true ? Sure o1 and o2 both have no value (ie null ), but they aren't from the same type ( Integer vs Float ). I firstly thought false would have been printed.

Integer i = null;
Object o1 = (Object) i;
Float f = null;
Object o2 = (Object) f;
System.out.println(o1 == o2); // prints true

// in short:
System.out.println(((Object) ((Integer) null)) == ((Object) ((Float) null))); // prints true

All null values are untyped and are equal. You can pass it to different reference types but it makes no difference for comparison purposes.

It is not the null value which is typed but the reference to the null which can be typed.

A common question is what happens here

class A {
    public static void hello() { System.out.println("Hello World"); }

    public static void main(String... args) {
        A a = null;
        a.hello();
        System.out.println("a is an A is " + (a instanceof A)); // prints false.
    }
}

The compiler sees the type of a as an A so the static method is called. But the value referenced is null and untyped.

The only operations you can perform with null without causing a NullPointerException is to assign or pass it without examining it or comparing it with another reference.

BTW

In short: The compiler will select a method based on the type of the reference, at runtime the execution is based on the class of the object referenced. At runtime null is treated as any type or no type or you get a NullPointerException if you try to dereference it.

"==" in Java checks to see if it is the same instance rather than simply "are they equal?". There is no concept of multiple instances of null in Java. If you compare null to null, you will always receive true regardless of type.

The reason why you cannot then pass null as an argument to a method with the same name as another with different parameter types is because either method could be a candidate to be called without further type context. Rather than guess which one that might be, it correctly indicates an error.

see http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.1

null belongs to the "null type". The "null type" has only one value - the null .

The null type is a subtype of every reference type. Therefore we can do

Integer i = null;   
(Integer)null

In another word, null is a valid value in every reference type.

(Think of a type as a set of values; the types of a value is the sets it belongs to; "subtype" means "subset". )

Given the above example, we can admit that null is NOT typed: when you call m1(null) , compiler cannot determine the type of the actual parameter and cannot decide which method to invoke. All nulls are equal and not typed, and so (null==null)==true .

Null does not have a type, but a reference (to null or anything else) has a type. We can declare two reference variables with different types, but the null they refer to is the same thing in both cases:

Integer a = null;
Double  b = null;

In your example,

m1((Integer) null);

the compiler uses the type of the reference it is passed to work out which overloaded method to call, not the type of the null value itself.

In your example it proves that the compiler cannot identity the type (of null) and decide which method to call. So you have to explicity give the type. Also null == null will be always true; no matter whatever cast you do it doesnt change or give null a type.

This post has a long description on null .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM