Overloaded Methods called with null

O

Oliver Brausch

Hello,
I would have to decompile some java code and the decompiler yields:

void a1(C1 c1) {
....
}

void a1(C2 c2) {
....
}

void a1() {
this.a1(null);
}

This can't be correct! Of course this is not possible. E.g.
this.a1((C1)null); would be correct! But how do I know if C1 or C2? The
Decompiler has not done this well! But the problem is that all
decompilers do this error!

Who knows what to do now?
 
M

Michael Redlich

Oliver said:
void a1() {
this.a1(null);
}

This can't be correct! Of course this is not possible. E.g.
this.a1((C1)null); would be correct! But how do I know if C1 or C2? The
Decompiler has not done this well! But the problem is that all
decompilers do this error!

Who knows what to do now?

Decompiling is obviously not a trivial task. The Java decompilers are
all different, and none of them decompile with total accuracy. It is
quite possible that you may be trying to decompile class files that
have been obfuscated. Have you tried to decompile class files (such as
your own) that you know for sure haven't been obfuscated?

Which decompiler(s) are you using? I have experimented with Cavaj
(http://www.bysoft.se/sureshot/cavaj/) and JODE
(http://jode.sourceforge.net/).

For more information about decompiling and obfuscating, check out a
great article written by Greg Travis at
http://www-128.ibm.com/developerworks/java/library/j-obfus/.

Mike.
 
R

Roedy Green

This can't be correct! Of course this is not possible. E.g.
this.a1((C1)null); would be correct!

You can't cast null to a type. Null is already is permitted for
every type. The decompiler is not showing you the full names of the
methods with signatures.

Perhaps a different disassembler would make it clear what is
happening, or look at the hex bytes codes directly.
see http://mindprod.com/jgloss/disassembler.
 
S

Stefan Ram

Roedy Green said:
You can't cast null to a type.

"The null reference can always be cast to any reference type."

The Java Language Specification, Third Edition, 4.1
 
T

Tim B

Oliver Brausch said:
Hello,
I would have to decompile some java code and the decompiler yields:

void a1(C1 c1) {
...
}

void a1(C2 c2) {
...
}

void a1() {
this.a1(null);
}

This can't be correct! Of course this is not possible. E.g.
this.a1((C1)null); would be correct! But how do I know if C1 or C2? The
Decompiler has not done this well! But the problem is that all
decompilers do this error!

Who knows what to do now?

What can't be correct? If C2 extends C1 or vise versa, this is legal code. I
haven't looked at the language specifications for this, but a bit of
experimenting shows that null is (effectively) cast to the most specific
class possible when there is otherwise an ambiguity.
 
O

Oliver Brausch

Stefan said:
"The null reference can always be cast to any reference type."

The Java Language Specification, Third Edition, 4.1

Of course you can cast null. And I have found a switch that the
decompiler does it.
 
R

Roedy Green

Of course you can cast null. And I have found a switch that the
decompiler does it.

I doubt though that, if you looked with Javap -c, you will ever find
null being cast. It does not do anything. You may cast a null
reference, but not the null literal.

If you did, it could be removed by an optimiser.

I think what you are seeing is just an artifact of the decompiler to
let you know which alternate overload it is using. There is likely not
actually a checkcast instruction.
 
S

Stefan Ram

Roedy Green said:
It still is just a null though isn't it? Null does not have a type.

In Java, expressions might have a "type".

An expression is not a value. It is an entity of the source
code model. For a variable of a reference type »A« the
expression

( B )a

has the type »B« (assuming that there is such a relation
between the type »A« and the type »B«, that such a cast is
permissible). The expression »( B )a« has this type, and this
assertion can be made at write time. There is no need to run
the program to find the type of an expression. The expression
»( B )a« has this type regardless of whether the reference
variable »a« contains the value »null« or not.

The same holds for the type of the expression »( B )null«.

So, while you are right in so far as the /value/ null indeed
might not have a type (a value being an entity of the run-time
model), the expression »( B )null«, which is an entity of the
source-code model, has a type in Java.

I also believe that as a value "null" does not have a type.
In physics, »1 m« (meter) is not »1 s« (second), but by the
meaning of the mathematical »0« the assertion »0 m = 0 s«
should be true, because both sides are just »0«.
 
C

Chris Smith

Roedy Green said:
It still is just a null though isn't it? Null does not have a type.

Roedy, you're confusing type and class. Objects have class, and
references have type.

The null reference certainly does have a type. It's called "the null
type", and there are widening conversions available from the null type
to all other reference types. If you cast explicitly to a reference
type, it's generally to remove ambiguity about which of several types
you'd like to match. This is useful in resolving method overloads.

As for your question, yes it is still just null. The value doesn't
change; only the type does. Dereferencing it will yield a
NullPointerException as usual. Because it doesn't point to an object,
you can't intelligently talk about the *class* of the object it points
to.

Basically, casting null to MyType is equivalent to:

MyType tmp1 = null;
someMethod(tmp1);

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
S

Stefan Ram

In Java, expressions might have a "type".

PS:

I would like to add two remarks:

One might want to distinguish between the "expression »null«"
and the "value »null«".

The term "cast" always refers to expression, one can not cast
references or objects in Java. So, what the JLS refers to is
not that one can change the type of the value »null«, but that
the expression »( A)null« is permissible for a reference type
»A« and has the type »A«.
 
C

Chris Smith

Oliver Brausch said:
Hello,
I would have to decompile some java code and the decompiler yields:

void a1(C1 c1) {
...
}

void a1(C2 c2) {
...
}

void a1() {
this.a1(null);
}

This can't be correct!

What is the relationship between the types C1 and C2? If one of them is
"maximally specific" then this is perfectly legal, and the method call
will match the maximally specific type.

For example:

class C1 { }
class C2 extends C1 { }

The code above is now legal, and the method call will reach the C2
overload.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
S

Stefan Ram

Chris Smith said:
Objects have class

The JLS3 seems to regard the class of an object as its type,
for example:

"New objects of the types Boolean, Byte, Short, Character,
Integer, Long, Float and Double may be implicitly created
by boxing conversion", JLS3, 4.3.1
references have type.

Expressions and objects have types, while references are
typeless pointers.

For example,

final java.io.InputStream alpha = System.in;

binds the variable "alpha" of type Typ "java.io.InputStream"
to a reference to an object of type
type "java.io.BufferedInputStream".

So while the variable and the object both have a type,
albeit not the same, just the reference does not have
a type.

name binding Referenz reference object
alpha -------------------> # ------------------> O
java.io.InputStream java.io.BufferedInputStream

Don't be mislead by the term "reference type". This does not
mean "type of a reference", but it is a type of a variable or
name that might denote a reference.
The null reference certainly does have a type. It's called "the null
type",

This is the type of the /expression/ »null«, not of its value.

"A null literal is always of the null type.", JLS3, 3.10.7

A »literal« is an entity of the source-code model, not of the
runtime model.

More directly my above assertion is confirmed in:

"There is also a special null type, the type of the
expression null", JL3, 4.1

The wording used is "of the /expression/ null". An
"expression" is an entity of the source code model, not a
value of the runtime model. The null type is not the type of
the value »null«, but the type of the expression »null«.
 
O

Oliver Brausch

Roedy said:
It still is just a null though isn't it? Null does not have a type.

Nobody answers and explains the stuff to him?
Just a hint: a casting sometimes shows the way....
 
R

Roedy Green

Roedy, you're confusing type and class. Objects have class, and
references have type.

I am thinking in terms of the JVM. You are thinking in terms of the
JLS. References have an associated class too, that's how you declare
them. I am well aware the reference can be null or can point to an
object a subclass of the one mentioned in the declaration.
 
C

Chris Smith

Roedy Green said:
I am thinking in terms of the JVM. You are thinking in terms of the
JLS.

In that case, references have a set of known facts about the class of
any object they point to... a set that grows larger, for example, with
checkcast bytecodes. Nevertheless, the fact remains that this knowledge
about the class of any object the reference points to functions as a
type, and is distinct from the class of the object (though it does
constrain the latter).

When you cast null to a type, the resulting checkcast bytecode
instruction inserted into the method causes the VM verifier to acquire
knowledge about the type, which can be used to verify later access to
class members through that reference.

Of course, the overload resolution happens in the source compiler, so
the cast also affects that in a way that predates the existence of
bytecode.
References have an associated class too, that's how you declare
them.

Pick your terminology. Typically, the type of a reference (which is a
class name when written in source code) is called "type", and often
distinguished from "class".
I am well aware the reference can be null or can point to an
object a subclass of the one mentioned in the declaration.

Yet you asked about the effect of a cast of the null literal? There
must be something you're not well aware of.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Roedy Green

binds the variable "alpha" of type Typ "java.io.InputStream"
to a reference to an object of type
type "java.io.BufferedInputStream".

So while the variable and the object both have a type,
albeit not the same, just the reference does not have
a type.

This may be edging toward angels dancing on the head of a pin, but at
the JVM level the reference value itself is just an address or pointer
without type information. However, at the language level the
reference variable obviously DOES have a type as in your example
java.io.BufferedInputStream, and that type will be the name of some
class. So, at least informally, reference variables have a class.
 
R

ricky.clarkson

As far as I can see, in this discussion there are some terms used in
various ways. Here's the most granular:

Variable - e.g., List x; It has a type, and its value is a reference
(or a primitive value).
Reference - the value of a variable (or expression) whose type is not
primitive - simply a pointer to a memory address, no type.
Object - the actual instance of a class used at runtime. It has
multiple types, namely that of the class it is an instance of, all the
superclasses and all the interfaces that the class it is an instance of
implements, and all that the superclasses implement.

Roedy seems to be using Variable and Reference as indistinguishable,
which is not uncommon, and is quite convenient.

The null literal is the only permissible expression of the null type.

The null type can be silently or non-silently cast to any other type,
and the JLS dictates that given a choice between silently casting null
to one of two types, X and Y, if Y is a subtype of X, then Y is chosen.

So you might find yourself needing to do method((String)null) instead
of just method(null) to prevent ambiguous method call compile errors.

However, there is no need to even use the null keyword, except to
safeguard against broken code. [1]

[1]
http://en.wikibooks.org/wiki/Java_Programming/Preventing_NullPointerException
 
C

Chris Smith

However, there is no need to even use the null keyword, except to
safeguard against broken code. [1]

[1]
http://en.wikibooks.org/wiki/Java_Programming/Preventing_NullPointerException

That page must be some kind of joke.

The example code for avoiding null on that page doesn't even compile,
and if it were modified in a straight-forward way so that it did
compile, it wouldn't do the same thing as the original.

More to the point, the null value exists because it's helpful. The
techniques on that page make it exceedingly difficult to accomplish some
very basic tasks, and don't actually lead to safer programming. Is it
somehow more likely that you'll check a boolean flag rather than that
you'll check for a null value? Is it now considered acceptable to
modify a public interface to be less capable, just to adopt some wacko
idea of programming form? And you're now not allowed to create arrays
of any length that's not known at compile-time? Wow, these people must
like making their lives difficult.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

ricky.clarkson

Chris Smith,
That page must be some kind of joke.

More of a bin for some ideas I had late one night. I've modified the
code sample at the top and I think it is more accurate now.
Is it now considered acceptable to
modify a public interface to be less capable

That depends. The rules are not for general programming, per se, but
for avoiding NullPointerExceptions. New programmers find the
NullPointerException quite obtuse, and are used to error messages at
runtime being not their fault, from the rubbish software that they use
daily. This isn't conjecture, this is my observation.
And you're now not allowed to create arrays
of any length that's not known at compile-time?

Again, if you're interested in preventing NullPointerExceptions, then
this is a rule worth following. An ArrayList is much better at
ensuring that you don't access the null elements, and you can even
create an array from one anyway.

As well as new learners, these rules may be worth following if you
don't do enough interactive testing before deployment, or if you have
system or safety-critical systems. I don't know, I haven't evaluated
them.

But they do prevent NullPointerExceptions, so they fulfill the title of
the page.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top