I have a doubt regarding type conversion between numeric values. Below is a snapshot from the book java complete reference. It says integer literals are successfully converted to byte or short provided the range of the value defined fits into the range of byte/short. However, when I try to run the following program it throws an error. Kindly clarify. Thanks.
book
import java.util.Scanner;
class Test{
public static void main(String args[])
{ int a=10;
byte b=16;
b=a;
System.out.println(b);
}}
/tmp/IQOgFrykLL/Test.java:12: error: incompatible types: possible lossy conversion from int to byte
b=a;
^1 error
It says integer literals are successfully converted to byte or short
b=a doesn't involve an integer literal.
An integer literal is something like 10 or 16: an actual number that appears in the source code.
b=10 would work, because 10 is an int literal.
Actually, it's a bit more general than only working with int literals: you can make this assignment with any compile-time constant value.
For example, if you were to make a final, it would work, because then a would be a compile-time constant value, and essentially could then be replaced by the int literal 10 wherever it is used.
Note that the definition of "compile time constant" is quite strict: it has to be a literal, or a final variable initialized with a compile-time constant value.
Declaring a non-final variable and never changing its value doesn't make it compile-time constant: you have to tell the compiler that its value can't change via final.
Declaring a variable as final doesn't make it a compile-time constant either: the value you assign it has to be a compile-time constant too.
Related
So far I thought that effectively final and final are more or less equivalent and that the JLS would treat them similar if not identical in the actual behavior. Then I found this contrived scenario:
final int a = 97;
System.out.println(true ? a : 'c'); // outputs a
// versus
int a = 97;
System.out.println(true ? a : 'c'); // outputs 97
Apparently, the JLS makes an important difference between the two here and I am not sure why.
I read other threads like
Difference between final and effectively final
Effectively final variable vs final variable
What does a variable being “effectively final” mean?
but they do not go into such detail. After all, on a broader level they appear to be pretty much equivalent. But digging deeper, they apparently differ.
What is causing this behavior, can anyone provide some JLS definitions that explain this?
Edit: I found another related scenario:
final String a = "a";
System.out.println(a + "b" == "ab"); // outputs true
// versus
String a = "a";
System.out.println(a + "b" == "ab"); // outputs false
So the string interning also behaves differently here (I dont want to use this snippet in real code, just curious about the different behavior).
First of all, we are talking about local variables only. Effectively final does not apply to fields. This is important, since the semantics for final fields are very distinct and are subject to heavy compiler optimizations and memory model promises, see $17.5.1 on the semantics of final fields.
On a surface level final and effectively final for local variables are indeed identical. However, the JLS makes a clear distinction between the two which actually has a wide range of effects in special situations like this.
Premise
From JLS§4.12.4 about final variables:
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.29). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.22), and definite assignment (§16.1.1).
Since int is primitive, the variable a is such a constant variable.
Further, from the same chapter about effectively final:
Certain variables that are not declared final are instead considered effectively final: ...
So from the way this is worded, it is clear that in the other example, a is not considered a constant variable, as it is not final, but only effectively final.
Behavior
Now that we have the distinction, lets lookup what is going on and why the output is different.
You are using the conditional operator ? : here, so we have to check its definition. From JLS§15.25:
There are three kinds of conditional expressions, classified according to the second and third operand expressions: boolean conditional expressions, numeric conditional expressions, and reference conditional expressions.
In this case, we are talking about a numeric conditional expressions, from JLS§15.25.2:
The type of a numeric conditional expression is determined as follows:
And that is the part where the two cases get classified differently.
effectively final
The version that is effectively final is matched by this rule:
Otherwise, general numeric promotion (§5.6) is applied to the second and third operands, and the type of the conditional expression is the promoted type of the second and third operands.
Which is the same behavior as if you would do 5 + 'd', i.e. int + char, which results in int. See JLS§5.6
Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:
[...]
Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
In a numeric choice context, the following rules apply:
If any expression is of type int and is not a constant expression (§15.29), then the promoted type is int, and other expressions that are not of type int undergo widening primitive conversion to int.
So everything is promoted to int as a is an int already. That explains the output of 97.
final
The version with the final variable is matched by this rule:
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.29) of type int whose value is representable in type T, then the type of the conditional expression is T.
The final variable a is of type int and a constant expression (because it is final). It is representable as char, hence the outcome is of type char. That concludes the output a.
String example
The example with the string equality is based on the same core difference, final variables are treated as constant expression/variable, and effectively final is not.
In Java, string interning is based on constant expressions, hence
"a" + "b" + "c" == "abc"
is true as well (dont use this construct in real code).
See JLS§3.10.5:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.29) - are "interned" so as to share unique instances, using the method String.intern (§12.5).
Easy to overlook as it is primarily talking about literals, but it actually applies to constant expressions as well.
Another aspect is that if the variable is declared final in the body of the method it has a different behaviour from a final variable passed as parameter.
public void testFinalParameters(final String a, final String b) {
System.out.println(a + b == "ab");
}
...
testFinalParameters("a", "b"); // Prints false
while
public void testFinalVariable() {
final String a = "a";
final String b = "b";
System.out.println(a + b == "ab"); // Prints true
}
...
testFinalVariable();
it happens because the compiler knows that using final String a = "a" the a variable will always have the "a" value so that a and "a" can be interchanged without problems.
Differently, if a is not defined final or it is defined final but its value is assigned at runtime (as in the example above where final is the a parameter) the compiler doesn't know anything before its use. So the concatenation happens at runtime and a new string is generated, not using the intern pool.
Basically the behaviour is: if the compiler knows that a variable is a constant can use it the same as using the constant.
If the variable is not defined final (or it is final but its value is defined at runtime) there is no reason for the compiler to handle it as a constant also if its value is equal to a constant and its value is never changed.
I looked for a duplicate of this but don't see a replica similar enough to satisfy.
You can't instantiate abstract classes in Java, and Number is abstract, so why does this line compile:
Number num = 3;
If it was Integer num, it would get autoboxed, but does autoboxing somehow work for Number too, even though it's abstract? Or is something else happening?
Integer is a subclass of Number, so 3 gets autoboxed from int to Integer, then the Integer gets stored in the Number variable.
It’s not that auto-boxing works for Number. You are fully correct, the Number class is abstract and cannot be instantiated. Also no general mechanism for auto-boxing a primitive number into a Number object exists in Java.
It’s that auto-boxing works from int to Integer. The literal 3 is an int (with no exception). And Integer is a concrete subclass of Number, so putting a reference to an Integer into a variable declared as Number is trouble-free.
It may be a bit surprising that it works, I agree with you. The basic rule of auto-boxing is you can put an int where an Integer is expected, a double where a Double is expected, and so forth. We can hardly say that an Integer was necessarily expected on the right-hand side of your initialization. It seems they have extended the rule to be applicable here anyway. And it’s no doubt in the JLS somewhere (JLS: Java Language Specification).
Just for checking we may do:
Number num = 3;
System.out.println(num.getClass());
Output:
class java.lang.Integer
You may extend the rule one step further:
Object obj = 3;
It still gives you an Integer (not just an Object even though Object is a concrete class).
Link: Similar question: Does Java autobox when assigning an int to an Object? (you will also find the references to JLS there)
This question already has answers here:
Static vs Instance Variables: Difference?
(6 answers)
Closed 5 years ago.
static _____ defaultValue;
public static void main(String[] args){
System.out.println(defaultValue);
}
Options:
A. One
B. Two
C. Three
D. Four
The answer in my book:
C. Since defaultValue is an instance variable, it is automatically initialized to the corresponding value for that type. For double the default value is 0.0. By contrast, it is 0 for int, long, and short. Therefore Option C is correct.
Now my question is defaultValue is a static variable how can it be an instance variable? It should not have any initial value. Please correct me as I know I am wrong somewhere. I am studying for OCA java certification exam and I found this question in a book by Scott Selikoff and Jeanne Boyarsky.
Variables that are declared as a class member variable, be static or instance, and not assigned a value will be assigned their default value. Note defaultValue is a static class member variable.
It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Primitive Data Types
The default values that will be assigned are as follows.
Of the four primitive types given (double, int, long and short), each will be assigned with 0, however, the output depends on how the primitive type is converted to a String. The way in which a String is generated from a primitive is almost identical, just with distinct methods for each primitive type. Let's examine the int primitive type:
By calling System.out.println(int i) you effectively call System.out.print(int i) with a line.separator used to terminate the line, as described in the PrintStream documentation. The System.out.print(int i) method takes the string produced by String.valueOf(int i) which is translated into bytes according to the platform's default character encoding. Finally, the String documentation shows that String.valueOf(int i) acts as a wrapper for Integer.toString(int i)
Hence, the String value for a primitive type is generated found by invoking the toString() method with the primitive value as a parameter on the wrapper Class corresponding to the primitive type (Integer for int, Short for short, etc).
How do these methods convert their default value to a String? All of the primitive values in the question (double, int, long and short) are assigned a default value of 0 (0.0d for double). The toString(primitive_type value) for each of the wrapper classes state that:
Double :
if m is zero, it is represented by the characters "0.0"; thus, negative zero produces the result "-0.0" and positive zero produces the result "0.0". toString(double d)
Integer :
Returns a String object representing the specified integer. The argument is converted to signed decimal representation and returned as a string, exactly as if the argument and radix 10 were given as arguments to the toString(int, int) method. toString(int i)
If the magnitude is zero, it is represented by a single zero character '0' ('\u0030') toString(int i, int radix)
Long :
Returns a String object representing the specified long. The argument is converted to signed decimal representation and returned as a string, exactly as if the argument and the radix 10 were given as arguments to the toString(long, int) method. toString(long i)
If the magnitude is zero, it is represented by a single zero character '0' ('\u0030') toString(long i, int radix)
Short :
Returns a new String object representing the specified short. The radix is assumed to be 10. toString(short s) Note that inspecting the code shows that this method is simply a wrapper for return Integer.toString((int)s, 10);
Hence, int, long and short will all output the character '0' when the value is 0 whereas the double value will print the characters '0.0'.
The answer in your book is incorrectly motivated, as you suspected.
Since defaultValue is an instance variable
It is a static variable. If it was an instance variable, this code wouldn't even compile.
it is automatically initialized to the corresponding value for that type.
Correct, but this applies to both instance and static variables.
For double the default value is 0.0. By contrast, it is 0 for int, long, and short.
There is no 'by contrast' about it. The default values are really zero in all these cases. System.out.println() will print 0.0 in the case of double and float, but what's in the variable is indistuinguishable from zero.
Therefore Option C is correct.
There is no 'therefore' about it. There are several non sequiturs here, as well as several errors of fact.
I found this question in a book by Scott Selikoff and Jeanne Boyarsky.
Good to know, so we can avoid it.
What is written in the book is correct except the line where it is says "Since defaultValue is an instance variable". As defaultValue is a static variable it cannot be a instance variable but it is off course a class variable. As it is a class variable it is automatically initialized to the corresponding value for that type.
C. Since defaultValue is an instance variable - this statement is wrong, because defaultValue is not an instance variable - it's a class variable as its declaration contains static keyword. Static variables are associated with class enclosing them. Another worth mentioning fact is that the static variables are initialized before instance variables (instance variables doesn't contain static as their modifier - every instance has its own variable and any changes in that variable doesn't affect other instances' variables).
Now my question is defaultValue is a static variable how can it be an instance variable? It should not have any initial value. - this statement is wrong. It is not an instance variable, it's a class variable. Anyway it will have initial value, because only local variables are not initialized to their default value (local variables are those, whose scope is method they're declared in. For example, if you declared defaultValue in the scope of main() method or any other method, it wouldn't be initialized to its default value.
When program starts execution and you haven't assigned any specific value to your variables, variables containing primitive types are initialized to their default values (you can see the list of these default values at the link below) and those containing objects are initialized to null.
Here, at "Default Values" paragraph, is a list of values that are assigned to primitive types:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
The Java language documentation says:
If a primitive type or a string is defined as a constant and the value
is known at compile time, the compiler replaces the constant name
everywhere in the code with its value. This is called a compile-time
constant.
My understanding is if we have a piece of code:
private final int x = 10;
Then, the compiler will replace every occurrence of x in the code with literal 10.
But suppose the constant is initialized at run-time:
private final int x = getX(); // here getX() returns an integer value at run-time.
Will there be any performance drop (howsoever negligible it may be) compared to the compile-time constant?
Another question is whether the below line of code:
private int y = 10; // here y is not final
is treated in same way as compile-time constant by the compiler?
Finally, what I understand from the answers are:
final static means compile-time constant
just final means it's a constant but is initialized at run-time
just static means initialized at run-time
without final is a variable and wouldn't be treated as constant.
Is my understanding correct?
Compile time constant must be:
declared final
primitive or String
initialized within declaration
initialized with constant expression
So private final int x = getX(); is not constant.
To the second question private int y = 10; is not constant (non-final in this case), so optimizer cannot be sure that the value would not change in the future. So it cannot optimize it as good as constant value. The answer is: No, it is not treated the same way as compile time constant.
The JLS makes the following distinctions between final variables and constants:
final variables
A variable can be declared final. A final variable may only be
assigned to once. It is a compile-time error if a final variable is
assigned to unless it is definitely unassigned immediately prior to
the assignment (§16 (Definite Assignment)).
Once a final variable has been assigned, it always contains the same
value. If a final variable holds a reference to an object, then the
state of the object may be changed by operations on the object, but
the variable will always refer to the same object. This applies also
to arrays, because arrays are objects; if a final variable holds a
reference to an array, then the components of the array may be changed
by operations on the array, but the variable will always refer to the
same array.
A blank final is a final variable whose declaration lacks an
initializer.
constants
A constant variable is a final variable of primitive type or type
String that is initialized with a constant expression (§15.28).
From this definition, we can discern that a constant must be:
declared final
of primitive type or type String
initialized within its declaration (not a blank final)
initialized with a constant expression
What about compile-time constants?
The JLS does not contain the phrase compile-time constant. However, programmers often use the terms compile-time constant and constant interchangeably.
If a final variable does not meet the criteria outlined above to be considered a constant, it should technically be referred to as a final variable.
According to JLS, there is no requirement that "constant variable" should be static.
So "constant variable" maybe static or non-static (instance variable).
But JLS imposes some other requirements for a variable to be a "constant variable" (besides being just final):
being only String or primitive
initialized inline only, because it is final, and blank final is not allowed
initialized with "constant expression" = "compile-time constant expression" (see JLS quote below)
4.12.4. final Variables (JLS)
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).
15.28. Constant Expressions
A compile-time constant expression is an expression denoting a value
of primitive type or a String that does not complete abruptly and is
composed using only the following:
Literals of primitive type and literals of type String (§3.10.1,
§3.10.2, §3.10.3, §3.10.4, §3.10.5)
Casts to primitive types and casts to type String (§15.16)
The unary operators +, -, ~, and ! (but not ++ or --) (§15.15.3,
§15.15.4, §15.15.5, §15.15.6)
The multiplicative operators *, /, and % (§15.17)
The additive operators + and - (§15.18)
The shift operators <<, >>, and >>> (§15.19)
The relational operators <, <=, >, and >= (but not instanceof)
(§15.20)
The equality operators == and != (§15.21)
The bitwise and logical operators &, ^, and | (§15.22)
The conditional-and operator && and the conditional-or operator ||
(§15.23, §15.24)
The ternary conditional operator ? : (§15.25)
Parenthesized expressions (§15.8.5) whose contained expression is a
constant expression.
Simple names (§6.5.6.1) that refer to constant variables (§4.12.4).
Qualified names (§6.5.6.2) of the form TypeName . Identifier that
refer to constant variables (§4.12.4).
There might be a really small performance drop on some machines for private final int x = getX(); since that would involve at least one method call (besides the fact that this isn't a compile-time constant) but as you said, it would be negligible so why bother?
As for the second question: y isn't final and thus is not a compile time constant, since it might change at runtime.
The final keyword means that a variable will be initialized once and only once. A real constant need to be declared static as well.
So, none of your examples are treated as constants by the compiler. Nevertheless, the final keyword tells you (and to the compiler) that your variables will be initialized once only (in the constructor or literally).
If you need their values assigned at compile time your fields must be static.
Performance is not really that affected, but have in mind that primitive types are immutable, once you have created one it will hold that value in memory until the garbage collector removes it.
So, if you have a variable y = 1; and then you change it to y = 2; in memory the JVM will have both values, but your variable will "point" to the latter.
private int y = 10; // here y is not final
is treated in same way as compile time constant by the compiler ?
No. This is an instance variable, created, initialized an used at runtime.
Just keep in mind that in the following code, x is not compile time constant:
public static void main(String[] args) {
final int x;
x= 5;
}
private final int x = getX();
Will be called the first time your object is declared. The performance "drop" will depend on getX() but that's not the kind of things to create some bottleneck.
Simply speaking while compilation the compiler replaces the reference with the actual value specified, instead of using the reference parameter.
public static void main(String[] args) {
final int x = 5;
}
ie. while compilation the complier take the initialised value of 5 directly for compliation than using the reference variable 'x';
Please check this explanation
Is this autoboxing?
Object ob = 8;
Will the above code first wrap the int literal 8 in an Integer and then assign its reference to variable ob? Because the java language specification has nothing on this case.
Will the above code first wrap the int literal 8 in an Integer and then assign its reference to variable ob?
Yes. (Or rather, it will box the int value into an Integer object, and then assign the reference to the variable ob. The fact that the integer value is a literal is irrelevant here, really. It could be a method call returning int, for example.)
Because the java language specification has nothing on this case.
That's not true. I mean, it doesn't explicitly deal with assigning to Object, but it works the same way as normal conversions.
Section 5.1.7 of the specification deals with boxing, which would convert int to Integer... and then assigning an Integer reference to an Object variable is a normal reference conversion.
This specific case is detailed in the assignment conversions:
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 one of the following:
[...]
a boxing conversion optionally followed by a widening reference conversion
So in your case:
8 (int) === boxing ===> 8 (Integer) ==== reference widening ===> 8 (Object)