How to cast super class object to sub class object in Kotlin? - java

Here I am trying to converting superclass object to subclass. I am getting the runtime error as "class can not be cast".
Eg :
class Animal {}
class Cat : Animal() {}
class abc {
fun abcd(): Animal {
return Animal()
}
fun getData() {
val cat: Cat = abcd() as Cat //Giving me runtime error.
}
}

You can't cast a base class 'instance' to a descendant class, because a base class does not necessarily implement the behaviors of its descendants neither knows anything about them.
In your specific example the method abcd() returns an instance of the base class Animal, and therefore such can't be cast to Cat, since Animal may not have any of the behaviors defined in Cat.
An example, imagine you had also a Dog class, and both Cat and Dog implement different methods such as dog.fetch() and cat.jump(). Such behaviors don't exist in the base class Animal, and therefore it can't be explicitly cast to a specific animal.
The opposite is valid, so casting Cat to Animal, because Cat inherits the behaviors of its base class Animal.
Instead, what you can do is to instantiate a Cat in abcd(), and still return Animal:
fun abcd(): Animal {
return Cat()
}
This is valid, and the casting will work. But, you must pay attention to avoid potential ClassCastException's at runtime if mixing up derived classes, for example if instantiating a Dog while the return type is Animal and try to use it as Cat.
Small remark: I'm assuming the reason Animal isn't open in your example is just a copy/paste mistake, as it clearly needs such keyword to allow inheritance.

Maybe what you are trying to do is something like creating a type and based on what sub-type then do something, like this:
sealed class Animal
data class Cat(val...) : Animal()
data class Dog(val...) : Animal()
class YourMapper {
fun animal(condition: Type): Animal {
return when(condition) {
... -> Dog(...)
... -> Cat(...)
}
}
fun getData(condition: Type): Animal {
return animal(condition)
}
And then the usage is
val data = YourMapper().getData(condition)
when(data) {
is Dog -> {/*do something with your dog*/}
is Cat -> {/*do something with your cat*/}
}

I know this is an old question, but it's the first Google hit for the search "Kotlin how to cast superclass to subclass", so for prosperity:
How to cast to subcalss in Kotlin
use the "as" keyword as in the original question:
if(animal is Cat) {
Cat cat = animal as Cat
}
The original question
Short answer, you can't cast a superclass object to a subclass object. Casting only changes the type of the reference to the object, the object itself remains unchanged.
The Animal class in the question should almost certainly be marked as abstract. That way there's no possibility to accidentally instantiate non-specific animals, which is what happens in the question and causes the exception.
An Animal reference variable can absolutely be cast to a Cat, provided the object it references is a Cat. But in the question a non-specific Animal is instantiated, and then later attempted to cast to a Cat, but as it is not referencing a Cat object, this understandably throws an exception.
So unlike, say, casting an Int to a Double where the cast seemingly changes the type of the object, casting object references doesn't actually "change" the object, only how finely-grained your reference to it is.
Casting cannot turn a Dog into a Cat, it can only change you from examining an animal as a generic Animal, viewing properties commont to ALL animals, to examining it as a Cat or a Dog and additionally having access to the properties only Cats or Dogs have.

Related

Generics code fails to compile without intermediate variable

I am surprised that the first 2 lines of code in main below are allowed by the compiler. It seems to be trusting me when I say that getIt() will return a Dog even though the signature also allows a Cat to be returned.
public class GenericsAreWeird {
public static void main(String... args){
// This is fine
Dog d = getIt();
d.woof();
// This fails to compile
// getIt().woof();
// This compiles but gives a runtime ClassCastException
Cat c = getIt();
c.meow();
}
private static <T extends Animal> T getIt(){
return (T) new Dog();
}
public static class Animal {}
public static class Cat extends Animal{
public void meow(){}
}
public static class Dog extends Animal{
public void woof(){}
}
}
I generally trust Java generics to protect me from ClassCastExceptions by giving compiler errors, rather than telling me at runtime that something won't work, so allowing this seems broken.
It also seems counter-intuitive that:
Dog d = getIt();
d.woof();
is not exactly equivalent to:
getIt().woof();
the compiler needs the intermediate variable as a 'hint'.
Have generics always worked this way? Can someone point me to (or provide) a decent explanation of any other scenarios where the compiler fails to pick up a class-related error like this?
return (T) new Dog(); for the most part tells the compiler to
"shut up with your type checking, I know better than you that Dog will always be assignable to T"
to which the compiler replies
"okay, go ahead then, then you better take care of not ever calling this method expecting it to return a anything else / aCat"
Then you do call it expecting it to return a Cat and get a deserved ClassCastException. You get a runtime exception because you tell the compiler that you know it better (which you do not).
After type erasure your getIt() method will look very much like this:
private static Animal getIt(){
return new Dog();
}
But before the type erasure happens, the compiler sees, that you use a generic return type T extends Animal for the method! And thus, once it sees the line
Dog d = getIt();
it says: Ok, so T will be Dog in this particular case, so I need to insert a cast to Dog after type erasure like this:
Dog d = (Dog) getIt();
In the same way, for the call Cat c = getIt() it will resolve the type T to be Cat and add an according cast to Cat:
Cat c = (Cat) getIt();
But inside of your method the compiler warns you: Hey, are you sure, that the Dog you create will always be of type T? Remember, this is not guaranteed generally! So if you ignore this warning, you should know, what you are doing, taht's the point.
And finally, of course the call
getIt().woof()
will not compile, because in this case the compiler has no idea how to resolve the type T, so it will be just Animal, the upper limitation of T. It is not able to guess that it is a Dog only based on the call to the woof() method.
The following line:
getIt().woof();
fails because woof() is defined on Dog not Animal and getIt() returns a sub-class of Animal. Hence the compiler is unaware of woof().
You could try:
abstract class Animal { abstract void speak(); }
class Dog extends Animal { void speak() { // Dog specific implementation } }
class Cat extends Animal { void speak() { // Cat specific implementation } }
Then you could use:
getIt().speak();
You get a ClassCastException because the only information about the type returned by getIt() is that it is a sub-class of Animal. Assigning it to a variable of type Cat or Dog is unsafe. This would be true of any similar use of generics.
A common workaround is to define getIt() something like this:
<T extends Animal> T getIt(Class<T> clazz) {
// return an instance of the appropriate type based on clazz
}
You can use it thus:
Dog dog = getIt(Dog.class);

Casting an Object to an Interface

i have the following Classes and interfaces:
public interface if1 {}
public class ifTest implements if1 {}
public class HelloWorld {
public static void main(String[] args) {
//why does the following cast not work (Compiler error)
ifTest var3 = (if1) new ifTest();
}
}
Why does this cast not work? I get the following compile error: "Type mismatch: cannot convert from if1 to ifTest"
Inheritance denotes an is-a relationship. Any object of IfTest is-an If1. However, a reference of type If1 does not necessarily refer to an object of type IfTest.
In a textbook scenario, any Dog is an Animal but any Animal is not a Dog (it might be a zebra, elephant, deer, etc).
Casting takes the form:
A a = (B) c;
There are 2 steps involved:
You have any object c that is cast to type B.
That instance of B is then assigned to variable a (where A is a type that must be either equal to B or a super class of B for the compiler to be happy and for no ClassCastExceptions to occur at runtime.
Continuing the animal metaphor, you are casting Dog to an Animal in step 1, but then trying to assign that instance of an Animal to a variable of type Dog, which the compiler knows is not allowed.
The following would work because it casts IfTest to If1 and then assigning that If1 to IfTest.
if1 var3 = (if1) new ifTest();
EDIT As Lew points out in his comment below, this is what is referred to as a widening cast (because it goes from a specific type to a more generic, "wider" type. In this instance, the cast is not necessary because the compiler knows all references to objects of type IfTest by definition are also If1.
A more practical example would be if you had a reference to the interface and wanted to cast it to a IfTest. In this case, it's a "narrowing" cast because you're going from the generic type to a more specific, "narrower" type.
if1 var1 = (if1) new ifTest();
if (var1 instanceOf ifTest) {
ifTest var2 = (ifTest) var1;
}
Note the use of the instanceof to to ensure that var1 is in fact an instance of IfTest. While we know it is, in a real-world application If1 might have multiple subtypes so this will not always be true. The check prevents the cast from throwing a run-time ClassCassException.
TLDR: The important thing to know is what is inside the parenthesis must be a type the compiler knows can be assigned to the variable being assigned to.
Here you are trying to instantiate an interface. An interface is just like a template or something similar to a contract - the class which implements the interface must obey the contract and provide implementation of the methods.

What is the difference between up-casting and down-casting with respect to class variable

What is the difference between up-casting and down-casting with respect to class variable?
For example in the following program class Animal contains only one method but Dog class contains two methods, then how we cast the Dog variable to the Animal Variable.
If casting is done then how can we call the Dog's another method with Animal's variable.
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
Upcasting is casting to a supertype, while downcasting is casting to a subtype. Upcasting is always allowed, but downcasting involves a type check and can throw a ClassCastException.
In your case, a cast from a Dog to an Animal is an upcast, because a Dog is-a Animal. In general, you can upcast whenever there is an is-a relationship between two classes.
Downcasting would be something like this:
Animal animal = new Dog();
Dog castedDog = (Dog) animal;
Basically what you're doing is telling the compiler that you know what the runtime type of the object really is. The compiler will allow the conversion, but will still insert a runtime sanity check to make sure that the conversion makes sense. In this case, the cast is possible because at runtime animal is actually a Dog even though the static type of animal is Animal.
However, if you were to do this:
Animal animal = new Animal();
Dog notADog = (Dog) animal;
You'd get a ClassCastException. The reason why is because animal's runtime type is Animal, and so when you tell the runtime to perform the cast it sees that animal isn't really a Dog and so throws a ClassCastException.
To call a superclass's method you can do super.method() or by performing the upcast.
To call a subclass's method you have to do a downcast. As shown above, you normally risk a ClassCastException by doing this; however, you can use the instanceof operator to check the runtime type of the object before performing the cast, which allows you to prevent ClassCastExceptions:
Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
// Guaranteed to succeed, barring classloader shenanigans
Dog castedDog = (Dog) animal;
}
Downcasts can be expressed more succinctly starting from Java 16, which introduced pattern matching for instanceof:
Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog castedDog) {
// now castedDog is available here as in the example above
}
Down-casting and up-casting was as follows:
Upcasting: When we want to cast a Sub class to Super class, we use Upcasting(or widening). It happens automatically, no need to do anything explicitly.
Downcasting : When we want to cast a Super class to Sub class, we use
Downcasting(or narrowing), and Downcasting is not directly possible in Java, explicitly we have to do.
Dog d = new Dog();
Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting
d.callme();
a.callme(); // It calls Dog's method even though we use Animal reference.
((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly.
// Internally if it is not a Dog object it throws ClassCastException
Autoboxing-vs-Casting
Upcasting and downcasting are important part of Java, which allow us to build complicated programs using simple syntax, and gives us great advantages, like Polymorphism or grouping different objects. Java permits an object of a subclass type to be treated as an object of any superclass type. This is called upcasting. Upcasting is done automatically, while downcasting must be manually done by the programmer, and i'm going to give my best to explain why is that so.
Upcasting and downcasting are NOT like casting primitives from one to other, and i believe that's what causes a lot of confusion, when programmer starts to learn casting objects.
Polymorphism: All methods in java are virtual by default. That means that any method can be overridden when used in inheritance, unless that method is declared as final or static.
You can see the example below how getType(); works according to the object(Dog,Pet,Police Dog) type.
Assume you have three dogs
Dog - This is the super Class.
Pet Dog - Pet Dog extends Dog.
Police Dog - Police Dog extends Pet Dog.
public class Dog{
public String getType () {
System.out.println("NormalDog");
return "NormalDog";
}
}
/**
* Pet Dog has an extra method dogName()
*/
public class PetDog extends Dog{
public String getType () {
System.out.println("PetDog");
return "PetDog";
}
public String dogName () {
System.out.println("I don't have Name !!");
return "NO Name";
}
}
/**
* Police Dog has an extra method secretId()
*/
public class PoliceDog extends PetDog{
public String secretId() {
System.out.println("ID");
return "ID";
}
public String getType () {
System.out.println("I am a Police Dog");
return "Police Dog";
}
}
Polymorphism : All methods in java are virtual by default. That means that any method can be overridden when used in inheritance, unless that method is declared as final or static.(Explanation Belongs to Virtual Tables Concept)
Virtual Table / Dispatch Table : An object's dispatch table will contain the addresses of the object's dynamically bound methods. Method calls are performed by fetching the method's address from the object's dispatch table. The dispatch table is the same for all objects belonging to the same class, and is therefore typically shared between them.
public static void main (String[] args) {
/**
* Creating the different objects with super class Reference
*/
Dog obj1 = new Dog();
` /**
* Object of Pet Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry about it
*
*/
Dog obj2 = new PetDog();
` /**
* Object of Police Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry
* about it here even though we are extending PoliceDog with PetDog
* since PetDog is extending Dog Java automatically upcast for us
*/
Dog obj3 = new PoliceDog();
}
obj1.getType();
Prints Normal Dog
obj2.getType();
Prints Pet Dog
obj3.getType();
Prints Police Dog
Downcasting need to be done by the programmer manually
When you try to invoke the secretID(); method on obj3 which is PoliceDog object but referenced to Dog which is a super class in the hierarchy it throws error since obj3 don't have access to secretId() method.In order to invoke that method you need to Downcast that obj3 manually to PoliceDog
( (PoliceDog)obj3).secretID();
which prints ID
In the similar way to invoke the dogName();method in PetDog class you need to downcast obj2 to PetDog since obj2 is referenced to Dog and don't have access to dogName(); method
( (PetDog)obj2).dogName();
Why is that so, that upcasting is automatical, but downcasting must be manual? Well, you see, upcasting can never fail.
But if you have a group of different Dogs and want to downcast them all to a to their types, then there's a chance, that some of these Dogs are actually of different types i.e., PetDog, PoliceDog, and process fails, by throwing ClassCastException.
This is the reason you need to downcast your objects manually if you have referenced your objects to the super class type.
Note: Here by referencing means you are not changing the memory address of your ojects when you downcast it it still remains same you are just grouping them to particular type in this case Dog
I know this question asked quite long time ago but for the new users of this question.
Please read this article where contains complete description on upcasting, downcasting and use of instanceof operator
There's no need to upcast manually, it happens on its own:
Mammal m = (Mammal)new Cat(); equals to Mammal m = new Cat();
But downcasting must always be done manually:
Cat c1 = new Cat();
Animal a = c1; //automatic upcasting to Animal
Cat c2 = (Cat) a; //manual downcasting back to a Cat
Why is that so, that upcasting is automatical, but downcasting must be manual? Well, you see, upcasting can never fail. But if you have a group of different Animals and want to downcast them all to a Cat, then there's a chance, that some of these Animals are actually Dogs, and process fails, by throwing ClassCastException.
This is where is should introduce an useful feature called "instanceof", which tests if an object is instance of some Class.
Cat c1 = new Cat();
Animal a = c1; //upcasting to Animal
if(a instanceof Cat){ // testing if the Animal is a Cat
System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");
Cat c2 = (Cat)a;
}
For more information please read this article
Better try this method for upcasting, it's easy to understand:
/* upcasting problem */
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class Useanimlas
{
public static void main (String [] args)
{
Animal animal = new Animal ();
Dog dog = new Dog();
Animal ref;
ref = animal;
ref.callme();
ref = dog;
ref.callme();
}
}
Maybe this table helps.
Calling the callme() method of class Parent or class Child.
As a principle:
UPCASTING --> Hiding
DOWNCASTING --> Revealing
1.- Upcasting.
Doing an upcasting, you define a tag of some type, that points to an object of a subtype (Type and subtype may be called class and subclass, if you feel more comfortable...).
Animal animalCat = new Cat();
What means that such tag, animalCat, will have the functionality (the methods) of type Animal only, because we've declared it as type Animal, not as type Cat.
We are allowed to do that in a "natural/implicit/automatic" way, at compile-time or at a run-time, mainly because Cat inherits some of its functionality from Animal; for example, move(). (At least, cat is an animal, isn't it?)
2.- Downcasting.
But, what would happen if we need to get the functionality of Cat, from our type Animal tag?.
As we have created the animalCat tag pointing to a Cat object, we need a way to call the Cat object methods, from our animalCat tag in a some smart pretty way.
Such procedure is what we call Downcasting, and we can do it only at the run-time.
Time for some code:
public class Animal {
public String move() {
return "Going to somewhere";
}
}
public class Cat extends Animal{
public String makeNoise() {
return "Meow!";
}
}
public class Test {
public static void main(String[] args) {
//1.- Upcasting
// __Type_____tag________object
Animal animalCat = new Cat();
//Some animal movement
System.out.println(animalCat.move());
//prints "Going to somewhere"
//2.- Downcasting
//Now you wanna make some Animal noise.
//First of all: type Animal hasn't any makeNoise() functionality.
//But Cat can do it!. I wanna be an Animal Cat now!!
//___________________Downcast__tag_____ Cat's method
String animalNoise = ( (Cat) animalCat ).makeNoise();
System.out.println(animalNoise);
//Prints "Meow!", as cats usually done.
//3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
//All of them have their own noises and own functionalities.
//Uncomment below and read the error in the console:
// __Type_____tag________object
//Cat catAnimal = new Animal();
}
}
upcasting means casting the object to a supertype, while downcasting means casting to a subtype.
In java, upcasting is not necessary as it's done automatically. And it's usually referred as implicit casting. You can specify it to make it clear to others.
Thus, writing
Animal a = (Animal)d;
or
Animal a = d;
leads to exactly the same point and in both cases will be executed the callme() from Dog.
Downcasting is instead necessary because you defined a as object of Animal. Currently you know it's a Dog, but java has no guarantees it's. Actually at runtime it could be different and java will throw a ClassCastException, would that happen. Of course it's not the case of your very sample example. If you wouldn't cast a to Animal, java couldn't even compile the application because Animal doesn't have method callme2().
In your example you cannot reach the code of callme() of Animal from UseAnimlas (because Dog overwrite it) unless the method would be as follow:
class Dog extends Animal
{
public void callme()
{
super.callme();
System.out.println("In callme of Dog");
}
...
}
We can create object to Downcasting. In this type also. : calling the base class methods
Animal a=new Dog();
a.callme();
((Dog)a).callme2();

How to downcast a Java object?

I am trying to understand Java's polymorphism, and I have one question about downcasting an object.
Let's say for this example I have two subclasses Dog and Cat that inherit from a superclass Animal
From what I understood, the only way to downcast an object is if this Object is already of the good type, like this:
Animal a = new Dog();
Dog d = (Dog) a;
This works right?
But what if I want to create a regular animal without knowing what it would be, and then cast it when I know, how can I do that?
Animal a = new Animal();
Dog d = (Dog) a;
This will throw a ClassCastException at runtime right?
The only way I found to do that is to create a new Dog constructor that creates a dog from a regular animal:
Animal a = new Animal();
Dog d = new Dog(a);
with
public Class Dog extends Animal{
public Dog(Animal a){
super(a);
}
}
So my question is, how am I supposed to do this?
Am I doing it the best way?
Am I not supposed to do this at all, if I have to it means my program is not well conceived?
Is there a better way I missed?
Thanks a lot!
nbarraille
If you want to create an instance of a type that may vary depending upon non-local conditions, use an Abstract Factory (as described in the Design Patterns book).
In it's simplest form:
interface AnimalFactory {
Animal createAnimal();
}
class DogFactory implements AnimalFactory {
public Dog createAnimal() {
return new Dog();
}
}
Note also there is a difference between the static type of a reference and the dynamic type of the object. Even though you have an Animal reference, if the original object is a Dog, it still behaves like a Dog.
You should only cast to a class that the object really is, so if you have a Dog that extends Animal you can cast it to an Animal (because it is one) but you shouldn't cast an Animal to a Dog because not all Animals are Dogs. The Dog class may well have extra fields that are not implemented by the Animal class and so the cast doesn't make sense (what do you initialise those values to?).
Java is a strongly typed language, and that means you can only cast an object to a type it extends from (either a superclass or an interface).
Even if you "fake it", e.g. copy all a classes methods and fields, you just can't cast an object to a type it doesn't extend.
public class Foo{
public String phleem;
public void bar(){
}
}
public class Bar{
public String phleem;
}
public interface Baz{
public void bar();
}
Given the above code, you can't cast a Foo object to either a Bar or a Baz, although the class structure seems to imply that you could. There is no inheritance involved, so a ClassCastException is thrown.
Here you are talking about downcasting, so in this scenario always superclass should be used as a reference and child object should be pointed by that.
This usd basically in factory patter.

Java: Is the following a class or an object?

public class Animal
{
public Animal()
{
System.out.println("Animal");
}
}
public class Mammal extends Animal
{
public Mammal()
{
System.out.println("Mammal");
}
}
Is this an object or a class? If not, what would be an example of an Object?
These are classes.
new Animal() would be an object, i.e. an instance of a class.
Both Animal and Mammal are classes.
Animal a = new Animal();
The code above will result in a reference, a, that refers to an object of type Animal. Since Mammal extends Animal, you'd also be allowed to write:
Animal a = new Mammal();
Your reference type would still be Animal, but this time it's referring to an object of type Mammal.
The Theory of Forms typically refers to Plato's belief that the material world as it seems to us is not the real world, but only a shadow of the real world. Plato spoke of forms in formulating his solution to the problem of universals. The forms, according to Plato, are roughly speaking archetypes or abstract representations of the many types and properties (that is, of universals) of things we see all around us.
Epistemology (From: wikipedia)
To explain it with Plato: The class is a form, 'a shadow'. The 'universals', those many types and properties are the objects.

Categories

Resources