Java Forum / General / December 2005
Overloaded Methods called with null
Oliver Brausch - 27 Dec 2005 01:24 GMT 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?
Michael Redlich - 27 Dec 2005 02:57 GMT > void a1() { > this.a1(null); [quoted text clipped - 6 lines] > > 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.
Roedy Green - 27 Dec 2005 03:36 GMT >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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Stefan Ram - 27 Dec 2005 03:55 GMT >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
Oliver Brausch - 27 Dec 2005 09:40 GMT > >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 Of course you can cast null. And I have found a switch that the decompiler does it.
Roedy Green - 27 Dec 2005 10:11 GMT >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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Roedy Green - 27 Dec 2005 09:54 GMT > "The null reference can always be cast to any reference type." It still is just a null though isn't it? Null does not have a type.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Stefan Ram - 27 Dec 2005 15:13 GMT >>"The null reference can always be cast to any reference type." >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«.
Stefan Ram - 27 Dec 2005 15:51 GMT >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«.
Chris Smith - 27 Dec 2005 15:50 GMT > > "The null reference can always be cast to any reference type." > > 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);
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Stefan Ram - 27 Dec 2005 16:28 GMT >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«.
Roedy Green - 28 Dec 2005 08:03 GMT > binds the variable "alpha" of type Typ "java.io.InputStream" > to a reference to an object of type [quoted text clipped - 3 lines] > 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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
ricky.clarkson@gmail.com - 29 Dec 2005 11:45 GMT 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
Chris Smith - 29 Dec 2005 16:45 GMT > 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.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
ricky.clarkson@gmail.com - 29 Dec 2005 19:30 GMT 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.
John C. Bollinger - 30 Dec 2005 04:20 GMT > Chris Smith, > [quoted text clipped - 11 lines] > runtime being not their fault, from the rubbish software that they use > daily. This isn't conjecture, this is my observation. Where are all these faultless new programmers coming from? Many moons ago when I was a new programmer, I tended to think that any error message at runtime was *surely* my fault. Perhaps I'm strange that way, but doesn't it stand to reason that if I don't know very well what I'm doing then problems are more likely to arise from me not doing it correctly than from any other source? For that matter, I'm still the most likely cause of runtime errors in my programs, even now that I mostly do know what I'm doing.
NullPointerExceptions are obtuse to the Java newbie, I agree, but the solution is to educate him about the cause, not to saddle him with a bunch of code-convoluting rules. Those given in the Wikibooks article aren't even 100% reliable. (Nulls can enter the program through various methods' return values, for instance. Also, though its obvious, if one doesn't want to see NPEs then one shouldn't explicitly throw any.) What is the value of teaching rules that are not suitable for general programming?
I think the article is focused incorrectly. Rather than presenting coding rules that are likely to be at least as opaque as the NPEs themselves, why not explicitly educate about where null values come from? That's where all your rules seem to have come from anyway.
>>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. I disagree, but I do find the comment to representative of the article's approach. The problem is not with using arrays in general, nor with creating them via the "new Type[count]" syntax. It is with attempting to dereference an array element that has not been assigned a non-null value. Using Lists instead of arrays and initializing arrays with explicit initializers do reduce the chance of NPEs vs. "new Type[count]", but sometimes neither of the former gives you what you want. A better rule here would be "Initialize All Array Elements", where you could discuss that the elements are initialized to null if no array initializer is used. "Consider using Lists instead of Arrays" would be potentially useful as a separate rule.
 Signature John Bollinger jobollin@indiana.edu
Roedy Green - 28 Dec 2005 01:35 GMT >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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Chris Smith - 28 Dec 2005 07:38 GMT > 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.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Oliver Brausch - 27 Dec 2005 20:48 GMT > 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....
Tim B - 27 Dec 2005 04:35 GMT > Hello, > I would have to decompile some java code and the decompiler yields: [quoted text clipped - 17 lines] > > 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.
Chris Smith - 27 Dec 2005 15:52 GMT > Hello, > I would have to decompile some java code and the decompiler yields: [quoted text clipped - 12 lines] > > 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.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|