This puzzle asks the musical question, What does this program
print?
public class Abc {
public static void main(String[] args) {
String letters = "ABC";
char[] numbers = { '1', '2', '3' };
System.out.println(letters + " easy as " + numbers);
}
}
Solution 12: ABC
One would hope that the program prints
ABC easy as 123. Unfortunately, it does not. If you ran it, you found
that it prints something like ABC easy as [C@16f0472. Why is the output
so ugly?
Although char is an integral type, many libraries
treat it specially, because char values usually represent characters
rather than integers. For example, passing a char value to
println prints a Unicode character rather than its numerical code.
Character arrays get similar special treatment: The char[] overloading
of println prints all of the characters contained in the array, and the
char[] overloadings of String.valueOf and
StringBuffer.append behave analogously.
The string concatenation operator, however, is not defined in
terms of these methods. It is defined to perform string
conversion on both of its operands and then to concatenate the resulting
strings. String conversion for object references, which include arrays, is
defined as follows [JLS 15.18.1.1]:
If the reference is null, it is converted to the string "null". Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.
So what is the behavior of invoking toString on a
non-null char array? Arrays inherit the toString method from
Object [JLS 10.7], whose specification says, "Returns a string
consisting of the name of the class of which the object is an instance, the
at-sign character '@', and the unsigned hexadecimal representation of
the hash code of the object" [Java-API]. The specification for
Class.getName says that the result of invoking this method on the class
object for char[] is the string "[C". Putting it all together
gives the ugly string printed by our program.
There are two ways to fix it. You can explicitly convert the
array to a string before invoking string concatenation:
System.out.println(letters + " easy as " +
String.valueOf(numbers));
Alternatively, you can break the System.out.println
invocation in two to make use of the char[] overloading of
println:
System.out.print(letters + " easy as "); System.out.println(numbers);
Note that these
fixes work only if you invoke the correct overloading of the valueOf or
println method. In other words, they depend critically on the
compile-time type of the array reference. The following program illustrates this
dependency. It looks as though it incorporates the second fix described, but it
produces the same ugly output as the original program because it invokes the
Object overloading of println instead of the char[]
overloading:
// Broken - invokes the wrong overloading of println! class Abc { public static void main(String[] args) { String letters = "ABC"; Object numbers = new char[] { '1', '2', '3' }; System.out.print(letters + " easy as "); System.out.println(numbers); // Invokes println(Object) } }
To summarize, char arrays are not strings. To convert a char array to a string, invoke
String.valueOf(char[]). Some library methods do provide
stringlike support for char arrays, typically having one overloading
for Object and another for char[]; only the latter has the
desired behavior.
The lesson for language designers is that the char[]
type should probably have overridden toString to return the characters
contained in the array. More generally, the array types should probably have
overridden toString to return a string representation of the contents
of the array.
No comments:
Post a Comment
Your comments are welcome!