I have come across this example on http://www.javabeginner.com/learn-java/java-object-typecasting and in the part where it talks about explicit type casting there is one example which confuses me.
The example:
class Vehicle {
String name;
Vehicle() {
name = "Vehicle";
}
}
class HeavyVehicle extends Vehicle {
HeavyVehicle() {
name = "HeavyVehicle";
}
}
class Truck extends HeavyVehicle {
Truck() {
name = "Truck";
}
}
class LightVehicle extends Vehicle {
LightVehicle() {
name = "LightVehicle";
}
}
public class InstanceOfExample {
static boolean result;
static HeavyVehicle hV = new HeavyVehicle();
static Truck T = new Truck();
static HeavyVehicle hv2 = null;
public static void main(String[] args) {
result = hV instanceof HeavyVehicle;
System.out.print("hV is an HeavyVehicle: " + result + "\n");
result = T instanceof HeavyVehicle;
System.out.print("T is an HeavyVehicle: " + result + "\n");
result = hV instanceof Truck;
System.out.print("hV is a Truck: " + result + "\n");
result = hv2 instanceof HeavyVehicle;
System.out.print("hv2 is an HeavyVehicle: " + result + "\n");
hV = T; //Sucessful Cast form child to parent
T = (Truck) hV; //Sucessful Explicit Cast form parent to child
}
}
In the last line where T is assigned the reference hV and typecast as (Truck), why does it say in the comment that this is a Successful Explicit Cast from parent to child? As I understand casting (implicit or explicit) will only change the declared type of object, not the actual type (which shouldn't ever change, unless you actually assign a new class instance to that object's field reference). If hv was already assigned an instance of a HeavyVehicle class which is a super class of the Truck class, how can then this field be type cast into a more specific subclass called Truck which extends from the HeavyVehicle class?
The way I understand it is that casting serves the purpose of limiting access to certain methods of an object (class instance). Therefore you can't cast an object as a more specific class which has more methods then the object's actual assigned class. That means that the object can only be cast as a superclass or the same class as the class from which it was actually instantiated. Is this correct or am I wrong here? I am still learning so I am not sure if this is the correct way of looking at things.
I also understand that this should be an example of downcasting, but I am not sure how this actually works if the actual type doesn't have the methods of the class to which this object is being downcasted. Does explicit casting somehow change the actual type of object (not just the declared type), so that this object is no longer an instance of HeavyVehicle class but now becomes an instance of Truck class?
Reference vs Object vs Types
The key, for me, is understanding the difference between an object and its references, or put in other words the difference between an object and its types.
When we create an object in Java, we declare its true nature, which will never change (e.g. new Truck()). But any given object in Java is likely to have multiple types. Some of these types are obviously given by the class hierarchy, others are not so obvious (i.e. generics, arrays).
Specifically for reference types, the class hierarchy dictates the subtyping rules. For instance in your example all trucks are heavy vehicles, and all heavy vehicles are vehicles. Therefore, this hierarchy of is-a relationships dictates that a truck has multiple compatible types.
When we create a Truck, we define a "reference" to get access to it. This reference must have one of those compatible types.
Truck t = new Truck(); //or
HeavyVehicle hv = new Truck(); //or
Vehicle h = new Truck() //or
Object o = new Truck();
So the key point here is the realization that the reference to the object is not the object itself. The nature of the object being created is never going to change. But we can use different kinds of compatible references to gain access to the object. This is one of the features of polymorphism here. The same object may be accessed through references of different "compatible" types.
When we do any kind of casting, we are simply assuming the nature of this compatibility between different types of references.
Upcasting or Widening Reference Conversion
Now, having a reference of type Truck, we can easily conclude that it's always compatible with a reference of type Vehicle, because all Trucks are Vehicles. Therefore, we could upcast the reference, without using an explicit cast.
Truck t = new Truck();
Vehicle v = t;
It is also called a widening reference conversion, basically because as you go up in the type hierarchy, the type gets more general.
You could use an explicit cast here if you wanted, but it would be unnecessary. We can see that the actual object being referenced by t and v is the same. It is, and will always be a Truck.
Downcasting or Narrowing Reference Conversion
Now, having a reference of type Vechicle we cannot "safely" conclude that it actually references a Truck. After all it may also reference some other form of Vehicle. For instance
Vehicle v = new Sedan(); //a light vehicle
If you find the v reference somewhere in your code without knowing to which specific object it is referencing, you cannot "safely" argument whether it points to a Truck or to a Sedan or any other kind of vehicle.
The compiler knows well that it cannot give any guarantees about the true nature of the object being referenced. But the programmer, by reading the code, may be sure of what s/he is doing. Like in the case above, you can clearly see that Vehicle v is referencing a Sedan.
In those cases, we can do a downcast. We call it that way because we are going down the type hierarchy. We also call this a narrowing reference conversion. We could say
Sedan s = (Sedan) v;
This always requires an explicit cast, because the compiler cannot be sure this is safe and that's why this is like asking the programmer, "are you sure of what you are doing?". If you lie to the compiler you will throw you a ClassCastException at run time, when this code is executed.
Other Kinds of Subtyping Rules
There are other rules of subtyping in Java. For instance, there is also a concept called numeric promotion that automatically coerce numbers in expressions. Like in
double d = 5 + 6.0;
In this case an expression composed of two different types, integer and double, upcasts/coerces the integer to a double before evaluating the expression, resulting in a double value.
You may also do primitive upcasting and downcasting. As in
int a = 10;
double b = a; //upcasting
int c = (int) b; //downcasting
In these cases, an explicit cast is required when information can be lost.
Some subtyping rules may not be so evident, like in the cases of arrays. For instance, all reference arrays are subtypes of Object[], but primitive arrays are not.
And in the case of generics, particularly with the use of wildcards like super and extends, things get even more complicated. Like in
List<Integer> a = new ArrayList<>();
List<? extends Number> b = a;
List<Object> c = new ArrayList<>();
List<? super Number> d = c;
Where the type of a is a subtype of the type of b. And the type of c is a subtype of the type of d.
Using covariance, wherever List<? extends Number> appears you can pass a List<Integer>, therefore List<Integer> is a subtype of List<? extends Number>.
Contravariance produce a similar effect and wherever the type List<? super Number> appears, you could pass a List<Object>, which makes of List<Object> a subtype of List<? super Number>.
And also boxing and unboxing are subject to some casting rules (yet again this is also some form of coercion in my opinion).
You got it right. You can successfully cast an object only to its class, some of its parent classes or to some interface it or its parents implement. If you casted it to some of the parent classes or interfaces, you can cast it back to the original type.
Otherwise (while you can have it in source), it will result in a runtime ClassCastException.
Casting is typically used to make it possible to store different things (of the same interface or parent class, eg. all your cars) in the same field or a collection of the same type (eg. Vehicle), so that you can work with them the same way.
If you then want to get the full access, you can cast them back (eg. Vehicle to Truck)
In the example, I am pretty sure that the last statement is invalid and the comment is simply wrong.
When you make a cast from a Truck object to a HeavyVehicle like that:
Truck truck = new Truck()
HeavyVehicle hv = truck;
The object is still a truck, but you only have access to heavyVehicle methods and fields using the HeavyVehicle reference. If you downcast to a truck again, you can use again all the truck methods and fields.
Truck truck = new Truck()
HeavyVehicle hv = truck;
Truck anotherTruckReference = (Truck) hv; // Explicit Cast is needed here
If the actual object you are downcasting is not a truck, a ClassCastException will be throw like in the following example:
HeavyVehicle hv = new HeavyVehicle();
Truck tr = (Truck) hv; // This code compiles but will throw a ClasscastException
The exception is thrown because the actual object is not of the correct class, its an object of a superclass (HeavyVehicle)
The last line of code compiles and runs successfully with no exceptions. What it does is perfectly legal.
hV initially refers to an object of type HeavyVehicle (let's call this object h1):
static HeavyVehicle hV = new HeavyVehicle(); // hV now refers to h1.
Later, we make hV refer to a different object, of type Truck (let's call this object t1):
hV = T; // hV now refers to t1.
Lastly, we make T refer to t1.
T = (Truck) hV; // T now refers to t1.
T already referred to t1, so this statement didn't change anything.
If hv was already assigned an instance of a HeavyVehicle class which is a super class of the Truck class, how can then this field be type cast into a more specific subclass called Truck which extends from the HeavyVehicle class?
By the time we reach the last line, hV no longer refers to an instance of HeavyVehicle. It refers to an instance of Truck. Casting an instance of Truck to type Truck is no problem.
That means that the object can only be cast as a superclass or the same class as the class from which it was actually instantiated. Is this correct or am I wrong here?
Basically, yes, but don't confuse the object itself with a variable that refers to the object. See below.
Does explicit casting somehow change the actual type of object (not just the declared type), so that this object is no longer an instance of HeavyVehicle class but now becomes an instance of Truck class?
No. An object, once created, can never change its type. It can't become an instance of another class.
To reiterate, nothing changed on the last line. T referred to t1 before that line and it refers to t1 afterward.
So why is the explicit cast (Truck) necessary on the last line? We are basically helping just helping out the compiler.
We know that by that point, hV refers to an object of type Truck, so it's ok to assign that object of type Truck to the variable T. But the compiler isn't smart enough to know that. The compiler wants our assurance that when it gets to that line and tries to make the assignment, it will find an instance of Truck waiting for it.
The above code will compile and run fine. Now change above code and add following line
System.out.println(T.name);
This will make sure that you are not using the object T after downcasting hV object as Truck.
Currently, in your code you are not using T after downcast so everything is fine and working.
This is because, by explicitly cast hV as Truck, complier does complain considering that programmer as casted the object and is aware of the what object is been casted to what.
But at runtime JVM is not able to justify the casting and throws ClassCastException "HeavyVehicle cannot be cast to Truck".
To help better illustrate some points made above, I modified the code in question and add more codes to it with inline comments (including actual outputs) as follows:
class Vehicle {
String name;
Vehicle() {
name = "Vehicle";
}
}
class HeavyVehicle extends Vehicle {
HeavyVehicle() {
name = "HeavyVehicle";
}
}
class Truck extends HeavyVehicle {
Truck() {
name = "Truck";
}
}
class LightVehicle extends Vehicle {
LightVehicle() {
name = "LightVehicle";
}
}
public class InstanceOfExample {
static boolean result;
static HeavyVehicle hV = new HeavyVehicle();
static Truck T = new Truck();
static HeavyVehicle hv2 = null;
public static void main(String[] args) {
result = hV instanceof HeavyVehicle;
System.out.print("hV is a HeavyVehicle: " + result + "\n"); // true
result = T instanceof HeavyVehicle;
System.out.print("T is a HeavyVehicle: " + result + "\n"); // true
// But the following is in error.
// T = hV; // error - HeavyVehicle cannot be converted to Truck because all hV's are not trucks.
result = hV instanceof Truck;
System.out.print("hV is a Truck: " + result + "\n"); // false
hV = T; // Sucessful Cast form child to parent.
result = hV instanceof Truck; // This only means that hV now points to a Truck object.
System.out.print("hV is a Truck: " + result + "\n"); // true
T = (Truck) hV; // Sucessful Explicit Cast form parent to child. Now T points to both HeavyVehicle and Truck.
// And also hV points to both Truck and HeavyVehicle. Check the following codes and results.
result = hV instanceof Truck;
System.out.print("hV is a Truck: " + result + "\n"); // true
result = hV instanceof HeavyVehicle;
System.out.print("hV is a HeavyVehicle: " + result + "\n"); // true
result = hV instanceof HeavyVehicle;
System.out.print("hV is a HeavyVehicle: " + result + "\n"); // true
result = hv2 instanceof HeavyVehicle;
System.out.print("hv2 is a HeavyVehicle: " + result + "\n"); // false
}
}
Related
When learning generics in Kotlin, I read in a book the following :
In general, a class or interface generic type may be prefixed with out if the class has functions that use it as a return type, or if the class has val properties of that type. You can’t, however, use out if the class has function parameters or var properties of that generic type.
I understand what the rule says, but i will be happy to understand (by examples) what may be without this rule (i.e there weren't constraint when using out when declaring a generic Class/Interface), and also why it isn't "dangerous" that the return type can be from type T and still class/Interface can contain out T.
Example where can't understand what is the problem that class property will behave as covariant:
class Pet{....}
class Dog:Pet{...}
class PetSomething <T : Pet>
{
T t;
public fun petDoSomething(T t)
{
.... // what can be the problem here?
}
}
class DogSomething
{
dogDoSomething()
{
d : Dog = Dog()
petDoSomething(d)
//what is the problem here???
}
}
In addition the book display the following code:
abstract class E<out T> (t:T) { val x = t }
and the code is being compiled although generic type is an input of constructor. Doesn't it break the rule?
You quoted: "You can’t, however, use out if the class has function parameters or var properties of that generic type."
A constructor is not a member function or property, so it is not subject to this rule. It is safe to use the type for a parameter at the site of the constructor, because the type is known when you are constructing it.
Consider these classes:
abstract class Pet
class Cat: Pet()
class Dog: Pet()
class PetOwner<out T: Pet>(val pet: T)
When you call the PetOwner constructor and pass in a Cat, the compiler knows you are constructing a PetOwner<out Cat> because it knows the value passed to the constructor satisfies the type of <out Cat>. It doesn't have to upcast Cat to Pet before the object is constructed. Then the constructed object can be safely upcast to PetOwner<Pet> because no T is ever going to be passed to the instance again. There is nothing unsafe that can happen, because no casting is done to the parameter.
Function parameters and var properties would be unsafe for an out type because the object is already constructed and might have been passed to some variable that has already upcast it to something else.
Imagine that the compiler let you define out T for a var property like this:
class PetOwner<out T: Pet>(var pet: T)
Then you could do this:
val catOwner: PetOwner<out Cat> = PetOwner(Cat())
val petOwner: PetOwner<out Pet> = catOwner
petOwner.pet = Dog()
val cat: Cat = catOwner.pet // ClassCastException!
The type safety rules prevent this scenario from being possible. But this isn't possible for a val constructor parameter. There is no way to pass the object to other variables and upcast its type in between passing the parameter to the constructor and having an instance that you can pass around.
The problem is this:
val x = DogSomething()
val y: PetSomething<Pet> = x // would be allowed by out
y.petDoSomething(Cat())
Note that petDoSomething on DogSomething only has to handle Dogs.
and the code is being compiled although generic type is an input of constructor. Doesn't it break the rule?
It doesn't, because the constructor isn't a member in the relevant sense; it couldn't be called on y above.
First lets clearfy what do we get by prefixing a type parameter with out keyword. consider the following class:
class MyList<out T: Number>{
private val list: MutableList<T> = mutableListOf()
operator fun get(index: Int) : T = list[index]
}
out keyword here makes MyList covariant in T, which essentially means you can do the following :
// note that type on left side of = is different than the one on right
val numberList: MyList<Number> = MyList<Int>()
if you remove the out keyword and try to compile again, you will get type mismatch error.
by prefixing the type parameter with out, you are basically declaring the type to be a producer of T's, in the example above MyList is a producer of Numbers.
which means no matter if you instantiate T as Int or Double or some other subtype of Number, you will always be able to get a Number from MyList (Because every subtype of Number is a Number). which also allows you to to do the following:
fun process(list: MyList<Number>) { // do something with every number }
fun main(){
val ints = MyList<Int>()
val doubles = MyList<Double>()
process(ints) // Int is a Number, go ahead and process them as Numbers
process(doubles) // Double is also a Number, no prob here
}
// if you remove out, you can only pass MyList<Number> to process
Now lets answer With out keyword why T should only be in return position? and what can happen without this constraint?, that is if MyList had a function taking T as parameter.
fun add(value: T) { list.add(T) } // MyList has this function
fun main() {
val numbers = getMyList() // numbers can be MyList<Int>, MyList<Double> or something else
numbers.add(someInt) // cant store Int, what if its MyList<Double> ( Int != Double)
numbers.add(someDouble) // cant do this, what if its MyList<Int>
}
// We dont know what type of MyList we going to get
fun getMyList(): MyList<Number>(){
return if(feelingGood) { MyList<Int> () }
else if(feelingOk> { MyList<Double> () }
else { MyList<SomeOtherSubType>() }
}
that is why constraint is required, its basically there to guarantee type safety.
as for abstract class E<out T> (t:T) { val x = t } being compiled, Kotlin In Action has following to say
Note that constructor parameters are in neither the in nor the out
position. Even if a type parameter is declared as out, you can still
use it in a constructor parameter. The variance protects the class
instance from misuse if you’re working with it as an instance of a
more generic type: you just can’t call the potentially dangerous
methods. The constructor isn’t a method that can be called later
(after an instance creation), and therefore it can’t be potentially
dangerous.
If I have super class (Animal) and a sub class (Cat).
What does the third point mean? And when we have to cast?
Cat obj = new Cat(); means creating an object from Cat class
Animal obj = new Animal(); means creating an object from Animal class
Animal obj = new Cat();
First lets understand Class, reference and Object. Suppose we have a class named SomeClass
SomeClass ref = new SomeClass();
Above we have an Object of SomeClass created in Heap and a reference variable refers to it. We have named the reference variable as ref. Object is present in heap and we can just access it using a reference. So Object type is of the actual class (on which new keyword has been applied). Reference variable type can be of actual class or its Parent class.
Now let us see the relationship of Inheritance. A class inheriting from another class share a Child-Parent relationship.
Child inherits the behaviour of its Parent and can then override some of the behaviour and also can add some additional behaviour. Hence Object of Child can be used at any place where Parent object is expected, as Child has all the behaviour of its Parent so invoking any behaviour present in the Parent will be handled by the Child.
Parent class do not know about the additional behaviour of its child class ( child class is written later in time.) Hence object of Parent can not be used at the places where Object of Child is expected (If additional behaviour of Child is invoked on Parent object then it will not be honoured).
Now let us assume we have classes ParentClass and ChildClass such that ChildClass inherits ParentClass
ParentClass reference = new ParentClass(); // Valid
ParentClass reference = new ChildClass(); //Valid
ChildClass reference = new ChildClass(); //Valid
ChildClass reference = new ParentClass();// Not Valid.
Note that
ParentClass reference = new ChildClass(); // Here Object is of type ChildClass and Reference is of type ParentClass.
Now when to cast. Any place expecting the object of ParentClass, there is no need to cast, both the objects (of ParentClass or of ChildClass) are fine.
Any place expecting the Object of type ChildClass but if we have a case like below then casting is needed.
public void someMethod(ChildClass expected){
//some implementation
}
ParentClass ref = new ChildClass();
someMethod(ref);//Invalid : Compilation Issue
someMethod((ChildClass)ref);// Valid
ParentClass anotherRef = new ParentClass();
someMethod(anotherRef); // Invalid : Compilation Issue
someMethod((ChildClass)ref); //Invalid, compiles but Runtime it will fail.
Thumb rule : Child is Child, Child is Parent, Parent is Parent , Parent is not Child.
Another example for understanding.
public abstract class List{
public abstract void add(int element);
public abstract void remove(int element);
public int size();
}
public class Application{
private List listReference;
public void setList(List ref){
listReference = ref;
}
}
//Now you may create sub classes as below
public class ArrayList extends List{
// all the abstract methods of List have been implemented
}
public class LinkedList extends List{
//all the abstract methods of List have been implemented
}
Now in main method you can pass ArrayList or LinkedList or any other implementation.
public class Init{
public static void main(String[] args){
Application app = new Application ();
app.setList(new LinkedList());
//or you can set it like this
List listRef = bew ArrayList();
app.setList(listRef);
//or you can set it like this
LinkedList linkedListRef = new LinkedLiet();
app.setList(linkedListRef);
}
}
Notice that the method setList() accepts List type of reference and we can provide any implementation of the List abstraction. This leads to a flexible design.
Classes should be dependent on the abstraction. Programming to interface is a Design Principle which leads to easy maintenance of the application code.
The reason why this is confusing on the face of it is that it is not something that you would typically do in real code, except in the case of a Factory.
As hinted at in Zabuza's comment, you can do this because a Cat 'is-a' kind of Animal and so you can assign an object of type Cat to an object of type Animal. But you can't do the assignment the other way of course, because an Animal is not a kind of Cat.
Now, there are some lurking issues that come with actually being able to create an instance of the the supertype as well as the subtype that mean you typically wouldn't actually do this in real code because it complicates a lot of things down the road. What you would more likely do is make Animal an interface and have a GenericAnimal class that implements it, along with having Cat implement it.
Say you have an object that represents a zoo, and most zoos typically have a collection of animals. The most obvious way to represent this would be this:
java.util.Collection<com.myproject.Animal> zooAnimals;
So now imagine the zoo builds a new habitat, and it's for a lion. For the sake of the story assume we have a very lazy data model and instead of having a specific com.myproject.animals.cats.Lion subtype we just said "lions are cats, close enough". So to update the data structure that tracks all the animals and their names and addresses and favorite foods and whatever else, we might do this:
com.myproject.Animal newArrival = new com.myproject.animals.Cat("Larry the Lion", "Africa Exhibit", "Gazelles");
zooAnimals.add(newArrival);
Now imagine that the zoo continues to grow, and gets an Ostrich in the Africa habitat. And the same lazy data model applies so we just call it a Bird.
com.myproject.Animal newArrival = new com.myproject.animals.Bird("Oliver the Ostrich", "Africa Exhibit", "Whatever Ostriches Eat");
zooAnimals.add(newArrival);
Now actually writing that exact code would normally only happen in very specific cases inside a factory object or something, and realistically type hierarchies like this have a tendency to not work very well in practice at all, contrary to what a lot of us learned in Object Oriented Programming class, but for the sake of the question that is an example situation where you might do what you are asking about.
Lastly, you also asked when you have to cast. You would have to do this if you had code that needed to know about any special methods or fields that the Cat or Bird types have that Animal does not have. For instance the Cat type might have a property called tailLength because cats typically have tails and for whatever reason the zoo likes to keep track of that. Similarly the Bird type might have a property called wingSpan because birds have wings and we want to keep track of how big they are. The Animal type doesn't have any of these properties so if we get the object for the lion or the ostrich out of the zooAnimals collection (and maybe we looked at the name or something to figure out it was the lion) we would have to cast back to the Cat type in order to access the tailLength property. Same thing for the ostrich and it's wingspan.
for( Animal theAnimal : zooAnimals ){
if( theAnimal.getName().equals("Larry the Lion") ){
Cat theCat = (Cat)theAnimal;
System.out.println("Larry's tail is " + theCat.getTailLength() + " inches long";
}
else if( theAnimal.getName().equals("Oliver the Ostrich") ){
Bird theBird = (Bird)theAnimal;
System.out.println("Oliver's wingspan is " + theBird.getWingSpan() + " inches";
}
}
Again you probably wouldn't actually do something like that in real code, but perhaps it helps to illustrate the example.
we can achieve the output in two ways one is typecasting and one is without typecasting
A a=new B() // without typecaste
A a = (A)a// with Typecaste
in both ways we get same output.so, what is the use of typecasting
Let's assume that you have a list of Animals. and you have Tigers and Lions in it.
ArrayList<Animal> animals = new ArrayList<>();
//add some Tigers and some Lions
//sort so Tigers are at the beggining of the list
Tiger t = (Tiger)animals.get(0);
Without casting you will get type missmatch at compile time. With a cast you only risk ClassCastException which can be easy caught with a try-catch
It's just an example of a proper use of class casting in Java.
Casting is for "the opposite direction", i.e. for converting to a expression of a subtype of the original expression.
Example
Given
Object o = "Hello World";
String s = o;
does not compile, but
String s = (String) o;
compiles. This may yield a ClassCastException however, e.g. if a Integer was stored in o.
Casting has different uses. Unfortunately, your example doesn't exercise any useful example of casting since you create an instance of A (a) then cast it to an A.
What you need to understand is there are apparent types and actual types. An apparent type would be List<T> list;. Here we see that it's a list. But the actual type might be an ArrayList<T> (List<T> list = new ArrayList<>();). In this scenario we can, with care, cast the apparent type to the actual type. This would allow us to then use the functionality of the actual type. For example, let's look at some code; given:
List<Integer> list = new ArrayList<>();
ArrayList<Integer> aList;
LinkedList<Integer> lList = new LinkedList<>();
We can do this without issue (although dangerous in general)...
// Dangerous but OK with a cast
// list might not be an ArrayList
aList = (ArrayList<Integer>) list;
// Use ArrayList methods
aList.trimToSize();
list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
...but it's also possible to do:
aList = (ArrayList<Integer) list;
// Use ArrayList methods
aList.trimToSize();
// list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
The last snippet results in a ClassCastException because list isn't a LinkedList.
Casting goes beyond that though. Consider when you have two integers you want to divide. Without a cast you could end up with an integer result where a floating point is more appropriate. Consider:
int i = 2;
int j = 3;
System.out.println("No cast: " + i/j + " ;With cast: " + (double)i/j);
Output:
No cast: 0 ;With cast: 0.6666666666666666
So, it depends on the use case.
A a = new B();
will only works if B inherit from A.
If B inherit from A, the type cast is not required as B is a A. Type cast will be necessary if you need to type cast to a subclass:
A a = new B();
B b = (B) a;
While this would be illegal :
A a = new A();
B b = (B) a;
as a is not a B.
Java implicitly upcast with assignment, so in the code you've provided the casting operator is redundant; a is already of type A:
A a = new B(); // without typecast operator (implicit upcast)
A a = (A)a; // with redundant typecast operator
One reason to have a casting operator is that you may also wish to downcast (which is not done implicitly in Java). For instance, when a is a type A reference to an object of class B (e.g. when B is a subclass of A) one may need to downcast to access certain methods:
A a = new B(); // implicit upcast
C c = ((B)a).methodOfBOnly(); // explicit downcast
You may also want to check this question on why Java doesn't do implicit downcasting.
There can be times when upcasting needs to be done explicitly as well. For instance, if a class contains overloaded methods
C method(A x){/*does one thing*/}
C method(B x){/*does another*/}
and assuming b is of type B, the calls to method((A)b) and method(b) would behave differently.
A a=new B()
is applicable only when class B extends class A. In this way the extra methods that are available in class B other than class A will be available with reference a.
When you do this
A a = (A)a
Then actually you are down casting the object of class B into an object of class A. And it is true that child can be type cast to parent. After this statement the reference a will not be able to call any method of class B which were not in class A because now the reference a points to an object of class A.
It is useful in many scenarios.
For example, you want to have a collection of Objects that point to same base class. Instead of maintaining separate collections for each sub class, you maintain a single collection of base class. And then when you want to use any child object you type cast the base class object to child class object to do that.
ArrayList<Base> children = new ArrayList<Base>();
children.add(new Child1());
children.add(new Child2());
Console.WriteLine(((Child1)children.get(0)).getChildName());
Console.WriteLine(((Child2)children.get(1)).getChildName());
Now base class does not have any method named getChild1Name or getChild2Name. And you need to typecast object of base class to respective child class to do that.
Here is what JavaDoc says:
public final Class <?> getClass()
Returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class.
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
Returns:
The Class object that represents the runtime class of this object.
Now , I understand it is a native method , so it is is implemented in platform-dependent code. But what about the return type of this method.
public final Class<?> getClass()
Also , consider the code:
class Dog
{
#Override
public String toString()
{
return "cat";
}
}
public class Main
{
public static void main(String[] args)
{
Dog d= new Dog();
//Class<Dog> dd = new Dog(); Compile time error
System.out.println(d.getClass());
}
}
Output:
class Dog
So, my query lies in :
Return type of this method
toString method is not called . A similar post on this topic is :
Java. getClass() returns a class, how come I can get a string too?
The commented code which otherwise give compile time error.
The data for each object contains a reference to an object of class java.lang.Class, and this is returned by the method getClass. There is also one java.lang.Class object describing java.lang.Class.
Think of a Class object as the "blueprint" describing a certain class from which objects are being made. It stands to reason that blueprints also need a blueprint of their own (or else how would engineers know how to make blueprints).
These statements try to illustrate this.
Integer integer = 1;
Class<?> clazzInteger = integer.getClass();
System.out.println( "class of integer=" + clazzInteger );
Class<?> clazzClazzInteger = clazzInteger.getClass();
System.out.println( "class of class Integer's class=" + clazzClazzInteger );
String string = "x";
Class<?> clazzString = string.getClass();
System.out.println( "class of string=" + clazzString );
Class<?> clazzClazzString = clazzString.getClass();
System.out.println( "class of class String's class=" + clazzClazzString );
Output:
class of integer=class java.lang.Integer
class of class Integer's class=class java.lang.Class
class of string=class java.lang.String
class of class String's class=class java.lang.Class
A class has a name, just like anything described by a blueprint has a name which is not to be confused with the blueprint itself. If a class object appears in a certain context, its toString() method is called implicitly, and this returns the class' name. If you'd like to print all the nitty-gritty details of a class (akin to printing the blueprint itself) you'd have to write a lot of code - just look at the javadoc for java.lang.Class: there's an awful lot of information to be retrieved (as befits a blueprint).
At this point, we need to differentiate between a type and an instance of the type. Lets explain it with an example.
public class A {
public static void main(String[] args) {
Class<A> typeInformation = A.class; //Type information associated with type `A`
A instanceOfA = new A(); //actual instance of type `A`
}
}
Type
The reference 'typeInformation' in the above code is of the type Class keeping aside the generics for a while. This information will typically be residing in non-heap memory section. Following information is store against each of the type jvm loads :
The fully qualified name of the type
The fully qualified name of the type's direct superclass (unless the type is an interface or class java.lang.Object, neither of which have a superclass)
Whether or not the type is a class or an interface
The type's modifiers ( some subset of` public, abstract, final)
An ordered list of the fully qualified names of any direct superinterfaces
Instance
instaneOfA is a reference to the actual instance of the type A which points to an address in the heap memory.
Return type of getClass() is a generic Class type. Like many other types available in java - String, Integer etc, Class is also a type representing the type information associated.
toString() method is associated and invoked on an instance of the Dog class, not on the Dog type itself.
//Class<Dog> dd = new Dog(); Compile time error
This is due to Type mismatch occuring while assigning the result of expression in the right hand side to the Left Hand Side, which is not of the same type.
Class dd refers to a reference of Class type.
Dog is a different type altogether, and a new Dog() can be assigned to a reference of the type 'Dog'.
This link will help you understand the design aspects of java runtime environment
I have an answer for your Question 3,
This gives compile time error because
Reason 1: For a Class instance, You can only assign class object that represents the Dog class, but you can't assign the Dog class object directly.
For example: Class dd=Dog.class or Class dd=Class.forName("Dog");
is correct syntax.
Reason 2: The class Class is a final class but not a super class for Dog class. You go back to the concept of dynamic method dispatch in java,where you can only assign subclass objects to a superclass variable.
Hello I have a few questions regarding type casting and inheritance. I have been doing some reading and I understand the point and basics of type casting. However, I don't fully understand where I can and can't use it.
Consider this class:
class A{
public A(){}
}
A temp = new A();
temp = (Object)temp;
This code gives me the error "Cannot convert from type Object to type A". However, wouldn't this be converting from type A to type Object? Can you not type cast up the hierarchy?
Now my second question regards inheritance and such.
When you type:
Object temp = new A();
what is really happening? Is temp an A or is it an Object?
Here the excerpt from JLS 8.1.3:
If the class declaration for any other
class has no extends clause, then the
class has the class Object as its
implicit direct superclass.
Of course, Object itself is a bit special (JLS):
Each class except Object is an
extension of (that is, a subclass of)
a single existing class (§8.1.3) and
may implement interfaces (§8.1.4).
Every Class is a descendant of Object.
In your case, you are trying store an object of A into a Class object called A. This isn't going to work. You need to do:
Object testObject = (Object)temp;
This will store the Object into testObject, which has the type Object that you casted to.
Here it is working on ideone.
It's just because you can't assign superclass object to the subclass reference.
So you can't do:
temp = (Object)temp;
because it's the same as:
Object newObject = new Object();
A temp = newObject;
You will get the same compile error here.
Of course you can do something like that:
Object newObject = new Object;
A temp = new A();
newObject = temp;
You can do it because you can assign subclass to the superclass reference
The problem is in the last line. First you promise Java that temp is of type Object by the statement:
(Object) temp
Afterwards you try to assign an object that the compiler thinks is of type Object to a variable that should be of type A. So to conclude, the part where you cast temp to type Object is fine, the problem is when you afterwards try to assign it to a variable expecting something of type A.
For your second question, temp is an A. When creating an object with the new keyword, the type of the object will always be whatever comes right after. In your case A. Afterwards you then assign temp to a variable of type Object, but that does not change the actual type of temp. Having a variable of some type X just tells you that whatever the variable is pointing to is a subtype of X.
A a = (Object)temp;
"Cannot convert from type Object to type A". However, wouldn't this be converting from type A to type Object? Can you not type cast up the hierarchy?
You are correct that
(Object)temp;
is converting temp, which is an A to an Object. However, that's not what the compiler is complaining about. Now that you have, effectively,
A a = anObjectNOTAnA
(A = ... is invalid code. I've changed it to A a = ....)
It's saying that you cannot convert an Object back to an A, unless you explicitely cast it and potentially suppress the unchecked-cast warning:
A a = (A)anObjectNOTAnA
or
#SuppressWarnings("unchecked")
A a = (A)anObjectNOTAnA
Regarding your other question:
Object temp = new A();
What is really happening? Is temp an A or is it an Object?
When you cast an object of any type, it never changes the actual type of the underlying object. A new A() is always an A, whether its
A a = new A();
or
Object objButReallyA = new A();
or
#SuppressWarnings("unchecked")
A a = (A)((Object)new A());
If an A is stored in an Object, it's just a different "view" of the same object. In order to use the A specific functions, however, you must first revert it back to the A view:
objButReallyA.getAOnlyField(); //compile error
((A)objButReallyA).getAOnlyField(); //Okay