The SCJP Tip Line More About Conversions by Corey McGlone
This month we're going to do a quick extension of my last article.
In that article, we looked at the various types of conversion and casts
that can be done in Java. This week, I'm going to look at a specific
trick with casting that may very well appear on the exam - it most
certainly appears on most mock exams.
Assignment Conversion vs. Method Invocation Conversion
Let's start off by taking a look at this code snippet:
Source Code
public class Conversions
{
private static byte myMethod(byte b) // 1
{
return 32; // 2
}
public static void main(String[] args)
{
byte b = myMethod(50); // 3
System.out.println(b); // 4
}
}
So what's the output of that code? I sure hope you said that it
produces a compiler error, because it certainly does. Let's take a look
at all of the conversions that are taking place in that code - believe
me, there are a lot.
Let's start at Line 3, which is the first line that will be executed. What data type is 50?
Any integral literal is always considered an int by the compiler.
Therefore, line 3 is passing an int to a method that takes a byte as a
parameter. This is where our compiler error comes from. Passing a
parameter to a method invokes a Method Invocation Conversion.
A method invocation conversion can only perform an identity conversion
(such as casting a byte to a byte, which is trivial) or a widening
conversion. Obviously, casting an int to a byte is a narrowing
conversion, so the method invocation conversion can't handle it. Hence,
the compiler error. If we were passing a byte to a method that took an
int, no problem - that's a widening conversion. But an int to a byte?
That's a no-no. Let's modify line 3 to read like this:
byte b = myMethod((byte)50);
What does that do for us? Well, by first casting the int to a byte
(through our explicit cast), we are passing a byte to a method that
requires a byte. That's just an identity conversion so the method
invocation conversion works just fine.
So now let's jump to Line 2. There's a conversion happening here, as well. What type is 32? Obviously, 32 is an int, just as we saw that 50 was an int. What conversion is happening here? Well, look at the return type of that method - we're supposed to return a byte. But we're returning an int! That should cause a compiler error, right? Wrong. Rather than using a method invocation conversion to perform the conversion, the compiler is going to use an Assignment Conversion
(essentially assigning the value being returned to the return
variable). There's a trick to an assignment conversion, though - the
following comes straight from the JLS:
"Assignment conversion occurs when the value of an expression is
assigned (§15.26) to a variable: the type of the expression must be
converted to the type of the variable. Assignment contexts allow the
use of an identity conversion (§5.1.1), a widening primitive conversion
(§5.1.2), or a widening reference conversion (§5.1.4). In addition, a
narrowing primitive conversion may be used if all of the following
conditions are satisfied:
The expression is a constant expression of type byte, short, char or int.
The type of the variable is byte, short, or char.
The value of the expression (which is known at compile time,
because it is a constant expression) is representable in the type of
the variable.
If the type of the expression cannot be converted to the type of the
variable by a conversion permitted in an assignment context, then a
compile-time error occurs."
Essentially, that says that you can automatically assign a value to a
variable, even if that assignment would require a narrowing conversion,
as long as the value is known at compile time (a literal value, as we
have here, or a final variable) and that value "fits" into the target
type. In our case, we're trying to assign 32 to a byte. Well, 32 is a
literal, so we know the type at compile time and it certainly falls
within the range of a byte, which is from -128 to 127. Therefore, the
Assignment Conversion handles this conversion automatically by doing an
automatic narrowing cast.
Conclusion
Short update this week, but an important one. The differences between
method invocation conversions and assignment conversions are small, but
important. Certainly, such details about conversions can be considered
"nit-picking" but a lot of the SCJP exam falls into that realm. The
idea behind the SCJP exam is to have a good handle on the details of
the language and I've seen questions about this material on many mock
exams and the real SCJP exam.