Java casting implementation - java

I know how to use casting in Java but have a more specific question; could you please explain to me how the casting works (in memory)?
How is the variable type changed upon upcasting and downcasting?
How does the JVM know that it's safe to send this method to this object?
Thank you in advance.

Could you please explain me how the casting works ( in memory )?
It works at byte code level not really in memory
How the variable type is changed on upcasting and downcasting?
If it is a primitive with an special bytecode instruction, for instance from long to integer as in:
long l = ...
int i = ( int ) l;
The bytecode is: l2i if is a reference with the instruction checkcast
How the JVM knows that from this time it's safe to send this method to this object?
It doesn't, it tries to do it at runtime and if it fails throws an exception.
It is legal to write:
String s = ( String ) new Date();

Possible duplicate of the accepted answer to this question:
How does the Java cast operator work?
There's also quite an extensive explanation here, that covers all data types, etc.:
http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5

All casting of primitives is done in registers (like most operations) For primitives, in many cases, when down casting the lower bits are taken and for up casting, the sign is extended. There are edge cases but you usually don't need to know what these are.
upcasting/downcasting a reference works the same in that it checks the actual object is an instance of the type you cast to. You can cast which is neither upcast nor down cast.
e.g.
Number n = 1;
Comparable c = (Comparable) n; // Number and Comparable are unrelated.
Serializable s = (Serializable) c; // Serializable and Comparable are unrelated.

If you are interested in the inner workings of jvn concerning how casts work you may also check the jvm spec http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#25611

Related

int or Integer in java [duplicate]

This question already has answers here:
What is the difference between an int and an Integer in Java and C#?
(26 answers)
Closed 2 years ago.
I have seen many times in code that people use int or Integer to declare variable in beans. I know int is datatype and Integer is wrapper class.
My question is, in which condition int or Integer should be used and is there any advantage of either of them over another?
My question is, in which condition int or Integer should be used and is there any advantage of either of them over another?
Well, you should use the reference type Integer whenever you have to. Integer is nothing more than a boxed int. An Object with a single field containing the specified int value.
Consider this example
public class Ex {
int field1;
Integer field2;
public Ex(){}
}
In this case field1 will be initialized with the value 0 while field2 will be initialized with null. Depending on what the fields represent, both approaches might be advantageous. If field1 represents some kind of UUID, would you want it to be initialized with a zero value?
I wouldn't worry too much about the performance implications of Autoboxing. You can still optimize after you get your code running.
For more information take a look at the documentation
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Integer.html
You always use int, pretty much.
Integer should rarely be used; it is an intermediate type that the compiler takes care of for you. The one place where Integer is likely to appear is in generics, as int is simply not legal there. Here is an example:
List<Integer> indices = new ArrayList<Integer>();
int v = 10;
indices.add(v);
The above works: It compiles with no errors and does what you think it would (it adds '10' to a list of integer values).
Note that v is of type int, not Integer. That's the correct usage; you could write Integer here and the code works as well, but it wouldn't be particularly idiomatic java. Integer has no advantages over int, only disadvantages; the only time you'd use it, is if int is straight up illegal. Which is why I wrote List<Integer> and not List<int> as the latter is not legal java code (yet - give it a few versions and it may well be legal then, see Project Valhalla).
Note also that the compiler is silently converting your v here; if you look at the compiled code it is as if javac compiled indices.add(Integer.valueOf(v)) here. But that's fine, let the compiler do its thing. As a rule what the compiler emits and what hotspot optimizes are aligned; trust that what javac emits will be relatively efficient given the situation.
int is a primitive type, a value type for number literals.
it is used whenever and wherever you just want to do some basic arithmetical operation;
it is a value type, so it's stored in the Stack area of the memory, hence operations on it are much faster;
whenever it's needed, compiler implicitly and automatically casts back and forth (a.k.a Boxing and Unboxing) from int to Integer and vice versa;
Integer is a Class, which is a reference type and you instantiate an Object of that type.
you create an object of that class, which means, that you also have some methods and operations on that object;
any time you do some arithmetic operation on the instance of Integer, under the hood, it's still implemented by int primitives, and it's just wrapped into box/container;
it is a reference type / object, which is very important, as you can Serialize or Deserialize it;
it also has some very useful utility factory methods, like Integer.valueOf(..) for example, to parse the String as an integer;
it can be well used into declarations of the generic types and it, as a class, supports the hierarchy as well. For instance, it extends Number, and you can make use of this;
it is stored in the Heap area of the memory.
int is a primitive and Integer is an object .
From an memory footprint point of view , primitive consume less memory than object and also primitives are immutable (since they use pass by value ) .
Here is a good article on when to use what :
https://www.baeldung.com/java-primitives-vs-objects

Why is it possible to compare incompatible types by reference in Java?

Check out this snippet:
List<Integer> c = new ArrayList<>();
Map<String,Boolean> m = new HashMap<>();
if( c == m ) //no error here! WHY?
{
c = m; //"Incompatible types" error, as expected.
m = c; //"Incompatible types" error, as expected.
}
How come c == m gives no error?
I am using the javac of jdk1.8.0.20 and I have no reason to suspect that it disregards the java language specification, so this is with a fairly absolute level of certainty in the spec, so:
What is the point / purpose / usefulness of having something like this allowed by the spec?
Just because the types are inconvertible doesn't mean that are not equal objects. If the types are "Inconvertible" it means a cast is required to check the type is actually convertible.
interface Outputer extends Consumer<String>, Serializable { }
Outputer out = System.out::println;
Consumer<String> cs = out;
Serializable s = out;
System.out.println(s == cs); // prints true
// s = cs; // Inconvertible types, doesn't compile
s = (Serializable) cs; // compiles and runs fine.
cs and s are inconvertible types, yet they point to the same object and this prints true
It's permitted specifically because List and Map are interfaces.
We could imagine some class
// (please only imagine)
class ListMap implements List, Map {...}
Compile-time legality of reference equality (15.21.3) is the same as that of reference type casting (5.5.1). In short, since you can generally cast between any reference type and an interface, you can also generally compare reference equality of any type to an interface.
The permission seems more useful in the context of smaller interfaces like Comparable, Serializable, Iterable, etc., where a class is more likely to implement more than one.
The Incompatible types error appears because when the assignment is being triggered, an operation called Assignment conversion starts. What it does is:
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.
If the conversion fails, then a compile-time error is thrown.
However, an compile-time error is not thrown when the == operator takes place.
In Java, whenever you have objects, the system uses pointers. And when you use == on two objects, it compares their pointers. In other words, it checks whether the two pointers are pointing to the same object in memory. This is always a safe check to make.
Also, it should be noted that when inheritance (and polymorphism) is involved, it is possible to have multiple pointers of different types that point to the same object. Of course, that wasn't the case in your example. But as I said earlier, it is harmless to check whether two pointers are pointing to the same object since that check makes no assumptions about the classes involved.
When you write
if(c==m)
you are simply checking for #hashcode Which might be same for two object under certain circumstances so you might not be getting any error in that line!

Operator definition in java

int i = 10;
i++; // it ok primitive value can use ++.
Integer integer = 10;
integer++; // how it can use ++
MyClass myClass = new MyClass();
myClass++; // then why myclass can't use ++.
C++ has the ability to overload operators. The Java language considers this to be open to too much abuse (overloaded operators can be obfuscating) so it was never incorporated into Java.
Therefore, you can't write myClass++ as the syntax is not available to specify that operation.
But ++ does work on a selection of non-primitives. The mechanism exploited is called autoboxing. (Essentially the underlying plain-old-data type is extracted from the boxed type, incremented then re-boxed to the original reference type).
Somewhat related to this is the ability to apply += and + to java.lang.String instances. Simply put, this is a special case. Although fully aware of the risk of downvotes I regard this as one of the worst kludges in Java, particularly += which will create a new instance of a string (as strings themselves are immutable), and many Java programmers will be unaware of the effect this has on memory.
It is because of Java's autoboxing feature which is added in Java 1.5
The compiler will convert the statment as follow
Integer integer = 10;
integer.iniValue++;
You can try to add the compiler flag "javac -source 1.4" and it will return an error
From the Link provided in a comment by Konstantin V. Salikhov,
Integer has a defined method to return an int, which then has the ++ operator defined.
MyClass has no ++ operator, hence myClass++; is invalid
The method in question goes like:
Integer myInteger = 10;
myInteger.intValue++;
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes.
Operator overloading in Java has a description (as to it being not allowed) at Operator overloading in Java

Short object creation

I had a look to this post Java instantiate Short object in Java but did not exactly respond to what I am looking for.
Does anybody know why the first line (//1) gives an error whereas the second line (//2) does not
Short s = new Short(4);//1
short s1 = 4;//2 Here I know why it works it gets
//implicitly narrow converted into a short.
As stated in the code, I understand why the second line works fine, but what about the first line? Where is the sense of writing Short s = new Short((short)4);
Bottom line: why does it not cast it implicitly? It is a constant not a variable.
Thanks in advance.
You could define a constructor taking a 'short' and another taking an 'int' and language semantics would make your call to the constructor ambiguous. So you need to use strict type. Also, since Short is final, try using Short.valueOf((short) 4) to avoid unnecessary object allocation.
This is caused because Java use "search mechanizm" to find a constructor for int type. When you assing value to varialbe its type is defined and compiler can optimize the code. With constructor (or any other method) this is not possible.
When you say
Short s = new Short(4);
you are specifying an integer literal 4, not a short literal, and this is not permitted under the Java language specification for Method Invocation Conversion.
However, when you say
short s1 = 4;
this is subject to what the Java Language Specification calls a Narrowing Primitive Conversion, which is permitted even if it would lose precision.
You should do like below :
Short s = new Short((short) 4);
Reason :
Type of 4 is Integer/int and NOT Short. So you need to do explicit typecast to ensure that Short constructor takes compatible type.
It's just not supported.
With the other number object types, there is a literal for the value, numbers are int by default, but for long you have the L suffix, double has d and so on.
If you were to have new Short(int) throw an exception, then the constructor would be inconsistent with the other number constructors.
Trying to create a short primitive that is too big is tested at compile time, the same with byte.
If you did this:
byte b = 1000000;
Your code would not compile, rather than throw an exception.
So the behaviour is consistent when you take the compiler into account.

Casting variables in Java

I wonder if anyone could tell me how casting works? I understand when I should do it, but not really how it works. On primitive data types I understand partially but when it comes to casting objects I don't understand how it works.
How can a object with the type Object just suddenly be cast to, let's say, MyType (just an example) and then get all the methods?
Casting in Java isn't magic, it's you telling the compiler that an Object of type A is actually of more specific type B, and thus gaining access to all the methods on B that you wouldn't have had otherwise. You're not performing any kind of magic or conversion when performing casting, you're essentially telling the compiler "trust me, I know what I'm doing and I can guarantee you that this Object at this line is actually an <Insert cast type here>." For example:
Object o = "str";
String str = (String)o;
The above is fine, not magic and all well. The object being stored in o is actually a string, and therefore we can cast to a string without any problems.
There's two ways this could go wrong. Firstly, if you're casting between two types in completely different inheritance hierarchies then the compiler will know you're being silly and stop you:
String o = "str";
Integer str = (Integer)o; //Compilation fails here
Secondly, if they're in the same hierarchy but still an invalid cast then a ClassCastException will be thrown at runtime:
Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here
This essentially means that you've violated the compiler's trust. You've told it you can guarantee the object is of a particular type, and it's not.
Why do you need casting? Well, to start with you only need it when going from a more general type to a more specific type. For instance, Integer inherits from Number, so if you want to store an Integer as a Number then that's ok (since all Integers are Numbers.) However, if you want to go the other way round you need a cast - not all Numbers are Integers (as well as Integer we have Double, Float, Byte, Long, etc.) And even if there's just one subclass in your project or the JDK, someone could easily create another and distribute that, so you've no guarantee even if you think it's a single, obvious choice!
Regarding use for casting, you still see the need for it in some libraries. Pre Java-5 it was used heavily in collections and various other classes, since all collections worked on adding objects and then casting the result that you got back out the collection. However, with the advent of generics much of the use for casting has gone away - it has been replaced by generics which provide a much safer alternative, without the potential for ClassCastExceptions (in fact if you use generics cleanly and it compiles with no warnings, you have a guarantee that you'll never get a ClassCastException.)
Actually, casting doesn't always work. If the object is not an instanceof the class you're casting it to you will get a ClassCastException at runtime.
Suppose you wanted to cast a String to a File (yes it does not make any sense), you cannot cast it directly because the File class is not a child and not a parent of the String class (and the compiler complains).
But you could cast your String to Object, because a String is an Object (Object is parent). Then you could cast this object to a File, because a File is an Object.
So all you operations are 'legal' from a typing point of view at compile time, but it does not mean that it will work at runtime !
File f = (File)(Object) "Stupid cast";
The compiler will allow this even if it does not make sense, but it will crash at runtime with this exception:
Exception in thread "main" java.lang.ClassCastException:
java.lang.String cannot be cast to java.io.File
Casting a reference will only work if it's an instanceof that type. You can't cast random references. Also, you need to read more on Casting Objects.
e.g.
String string = "String";
Object object = string; // Perfectly fine since String is an Object
String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.
The right way is this:
Integer i = Integer.class.cast(obj);
The method cast() is a much safer alternative to compile-time casting.

Categories

Resources