Explicit casting from super-class to sub-class - java

public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
The assignment Dog dog = (Dog) animal; does not generate a compilation error, but at runtime it generates a ClassCastException. Why can't the compiler detect this error?

By using a cast you're essentially telling the compiler "trust me. I'm a professional, I know what I'm doing and I know that although you can't guarantee it, I'm telling you that this animal variable is definitely going to be a dog."
Since the animal isn't actually a dog (it's an animal, you could do Animal animal = new Dog(); and it'd be a dog) the VM throws an exception at runtime because you've violated that trust (you told the compiler everything would be ok and it's not!)
The compiler is a bit smarter than just blindly accepting everything, if you try and cast objects in different inheritence hierarchies (cast a Dog to a String for example) then the compiler will throw it back at you because it knows that could never possibly work.
Because you're essentially just stopping the compiler from complaining, every time you cast it's important to check that you won't cause a ClassCastException by using instanceof in an if statement (or something to that effect.)

Because theoretically Animal animal can be a dog:
Animal animal = new Dog();
Generally, downcasting is not a good idea. You should avoid it. If you use it, you better include a check:
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}

In order to avoid this kind of ClassCastException, if you have:
class A
class B extends A
You can define a constructor in B that takes an object of A. This way we can do the "cast" e.g.:
public B(A a) {
super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
// If B class has more attributes, then you would initilize them here
}

Elaborating the answer given by Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Here you are saying to the compiler "Trust me. I know d is really referring to a Dog object" although it's not.
Remember compiler is forced to trust us when we do a downcast.
The compiler only knows about the declared reference type. The JVM at runtime knows what the object really is.
So when the JVM at the runtime figures out that the Dog d is actually referring to an Animal and not a Dog object it says.
Hey... you lied to the compiler and throws a big fat ClassCastException.
So if you are downcasting you should use instanceof test to avoid screwing up.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Now a question comes to our mind. Why the hell compiler is allowing the downcast when eventually it is going to throw a java.lang.ClassCastException?
The answer is that all the compiler can do is verify that the two types are in the same inheritance tree, so depending on whatever code might have
come before the downcast, it's possible that animal is of type dog.
The compiler must allow things that might possible work at runtime.
Consider the following code snipet:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
However, if the compiler is sure that the cast would not possible work, compilation will fail. I.E. If you try to cast objects in different inheritance hierarchies
String s = (String)d; // ERROR : cannot cast for Dog to String
Unlike downcasting, upcasting works implicitly because when you upcast you are implicitly restricting the number of method you can invoke,
as opposite to downcasting, which implies that later on, you might want to invoke a more specific method.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Both of the above upcast will work fine without any exception because a Dog IS-A Animal, anithing an Animal can do, a dog can do. But it's not true vica-versa.

To develop the answer of #Caumons:
Imagine one father class has many children and there is a need to add a common
field into that class. If you consider the mentioned approach, you should
go to each children class one by one and refactor their constructors for the new field.
therefore that solution is not a promising solution in this scenario
Now take a look at this solution.
A father can receive an self object from each children. Here is a father
class:
public class Father {
protected String fatherField;
public Father(Father a){
fatherField = a.fatherField;
}
//Second constructor
public Father(String fatherField){
this.fatherField = fatherField;
}
//.... Other constructors + Getters and Setters for the Fields
}
Here is our child class that should implement one of its father
constructor, in this case the aforementioned constructor :
public class Child extends Father {
protected String childField;
public Child(Father father, String childField ) {
super(father);
this.childField = childField;
}
//.... Other constructors + Getters and Setters for the Fields
#Override
public String toString() {
return String.format("Father Field is: %s\nChild Field is: %s", fatherField, childField);
}
}
Now we test out application:
public class Test {
public static void main(String[] args) {
Father fatherObj = new Father("Father String");
Child child = new Child(fatherObj, "Child String");
System.out.println(child);
}
}
And here is the result :
Father Field is: Father String
Child Field is: Child String
Now you can easily add new fields to father class without being worried of your children codes to break;

The code generates a compilation error because your instance type is an Animal:
Animal animal=new Animal();
Downcasting is not allowed in Java for several reasons.
See here for details.

As explained, it is not possible.
If you want to use a method of the subclass, evaluate the possibility to add the method to the superclass (may be empty) and call from the subclasses getting the behaviour you want (subclass) thanks to polymorphism.
So when you call d.method() the call will succeed withoug casting, but in case the object will be not a dog, there will not be a problem

As it was said before, you can't cast from superclass to subclass unless your object was instantiated from the subclass in the first place.
However, there are workarounds.
All you need is a set of constructors and a convenience method that will either cast your object to Dog, or return a new Dog object with the same Animal properties.
Below is an example that does just that:
public class Animal {
public Animal() {}
public Animal(Animal in) {
// Assign animal properties
}
public Dog toDog() {
if (this instanceof Dog)
return (Dog) this;
return new Dog(this);
}
}
public class Dog extends Animal {
public Dog(Animal in) {
super(in);
}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = animal.toDog();
}
}

Related

Why casting is not possible from child to parent

I have a class Animal which has one child Dog.
class Animal {
public void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
#Override
public void makeSound() {
super.makeSound();
}
}
public static void main(String[] args) {
Dog dog = (Dog) new Animal(); // It compiles, but throws runtime exception.
dog.makeSound();
}
Here if we will cast child to parent, it will compile, but it will throw runtime exception - ClassCastException. Of course, there can be a case when the child will have a field or method which the parent doesn't. That's why we can't cast Dog to Animal. Also, there's no IS-A relationship. But why the cast is not possible, in case parent and child classes have only the same fields and methods?
I've got asked this question in the interview)
Thank you.
When the compiler sees that you are trying to cast the Animal object into a Dog, it "knows" that Dog is underneath Animal in the hierarchy, so it is possible that the animal is a dog, so it allows it. However, at runtime, it turns out that it is just an Animal, and is not a Dog, so the cast fails.
This is a weird case in which it is obvious in reading the program that the Animal is just an Animal and not a Dog because it was just created with "new Animal()", but the compiler doesn't know that--it just knows that it is an Animal. Compilers are smart, but they can't know everything. I hope that makes sense.

Java A bit confused with Polymorphic concept in Java

Example program:
class Animal {
public void eat() {
System.out.println(" Animal eats");
}
class Dog extends Animal {
public void eat(String s) {
System.out.println(" Dog eats" + s);
}
public class Demo {
public static void main(String args[]){
Animal a = new Dog();
Dog d = (Dog) a;
a.eat();
d.eat("Meat");
}
}
My question is why a.eat("Meat") is not reachable? Since a is Object during the time it's referring to Dog Object, it should allow to call eat("meat").
Can anyone clarify where am I going wrong?
You're trying to call method of subclass Dog through variable of base class Animal.
Java has strong typing, so if you declare variable of class Animal you can access only to methods and fields of Animal and its superclasses.
You can call eat("Meat") from Animal using casting ((Dog) a).eat("Meat") but you should avoid as much as possible such constructions.
Btw, your approach looks like a function overloading rather than polymorphism.
P.S. Maybe this article about strong typing will be helpful for you. And this one about difference between overloading and polymorphism.
Dog d = (Dog) a;
Here you are casting the Animal a to a Dog. However, this does not change the type of a. a is still an Animal hence you can only call eat() without a string.

How to Down Cast an Object in Java

I am working with an API in my company where I would like to create a subclass for an existing object. Here are the caveats:
I cannot modify the superclass
I cannot modify how the superclass object is instantiated
The example I see most commonly is a Dog as a subclass of Animal, so I will use that. Let's say you have this class in the API:
//API class, which I cannot modify
public class Animal(){
public void eat(){
//All animals can do this
}
}
Now I would like to create a class like this, which adds a few methods to Animal.
//My subclass, which I can modify
public class Dog extends Animal(){
public void fetch(){
//Only dogs can do this
}
}
So now let's say I have an instance of Animal (one that is not a Dog). I essentially need to downcast it into a Dog. I get that downcasting is not directly supported in Java, but is there any workaround for this?
public class AnimalExample{
public static void main(String[] args){
Animal animal = MyApi.getAnAnimal();
//Dog dog = (Dog) animal; ---throws a runtime error
Dog dog = Dog.getDog(animal); //Maybe something like this?
//Then I should be able to call both eat() and fetch()
dog.eat();
dog.fetch();
}
}
Again, I understand that downcasting is not directly supported. But there has to be some workaround for this, and I can't figure it out. I know that I could use a wrapper class (eg DogWrapper), but that would be a little more difficult than I'd like because I still frequently call the dozens of superclass methods.
UPDATE: I understand that it's not yet a Dog, but I was wondering if there was a way to convert it into a Dog. It basically sounds like, from what people are saying, that I either have to convert it manually (copy each attribute/method over one-by-one) or just use a Wrapper class. A Wrapper class seems a lot less messy, so unfortunately I'll just have to go that route. So DogWrapper will have a fetch() method and a getAnimal() method. So if I want the Dog to eat, then I have to call dog.getAnimal().eat(). I was avoiding having to do that, but I guess there's no way around it. Does anyone see anything simpler than that?
You can have a constructor which takes Animal and instantiates the Dog part of the object with defaults or as required.
public Dog (Animal animal) {
super(); // any instantiation that has to be done for animal
// Dog instantiation
// Use animal properties as required
}
Dog dog = new Dog(animal);
Also having a static method as you mentioned Dog.getDog(animal) is an option, depends on your coding preference.
Let's suppose I create a method that requires a Dog, but is meant to extend the Animal API. Sure, I could just make the signature like so:
public void doFetch(Dog dog)
But as I said, I want to extend the Animal API. Now, if the given Animal is not a Dog, I can't fetch. With that in mind, I can do the following:
public void doFetch(Animal fetcher) {
if(fetcher instanceof Dog) {
Dog dog = (Dog) fetcher;
... //Do fetchy things
return;
}
//If we reach this point, then the animal is not a dog
throw new IllegalArgumentException("fetcher is not a Dog!");
}
Now let's suppose, as in your case, I have an Animal that is not a dog, but I want it to be a Dog for some reason. In this case, I could convert any Animal into a dog using some kind of translator. I prefer to define things like this as static methods in the Dog class itself:
//Breaks the laws of nature by making a Dog from any Animal.
public static Dog fromAnimal(Animal animal) {
Dog dog = new Dog();
//Here you would set all the properties of the animal, e.g.:
dog.setName(animal.getName());
...
return dog;
}

Calling a function using Object type reference (holding a different instance)

I have a Dog class described as:
class Dog {
//data members
void bark() {
//Bark Algorithm
}
}
Now in another class which has the main method and in the main method, if I do the following:
Object dog = new Dog();
dog.bark();
Shouldn't it work as the "dog" reference is holding a Dog instance? Why is this not valid?
The language used here is Java.
Thanks for the help in advance.
Java is very strongly typed. Java compiler performs a method check at compile time, not at runtime. dog is declared as Object, so compiler checks if Object class has a method named bark(). It doesn't, so it throws a compiler error. This is how Java is designed.
Note that this is not a limitation of polymorphism per se, but a limitation of the implementation of polymorphism in Java. This exact same code would perfectly compile (and work) in a more dynamically typed language like Groovy, which also runs on the JVM.
The class Object does not have a method called bark. Therefore, your code would not compile.
However, this does not mean that the compiler decides what method to call purely based on the reference type. Your reference type decides what methods you CAN call, while the instance type will decide what you method you WILL call. This is the essential mechanism for polymorphism.
For example,
class Animal
{
void makeSound()
{
//Generic animal sound algorithm
}
}
class Dog extends Animal{
void makeSound()
{
//Bark Algorithm
}
}
Then
Animal dog = new Dog();
Animal animal = new Animal();
dog.makeSound(); //calls bark
animal.makeSound(); //generic animal sound
I think I got the solution here. The compiler decides which function to call based on the reference type and not on the instance type that reference holds.
Like in this case, just like the Dog class, many other animals can also can be instantiated and Object references can be used to refer to their objects on the heap, but not all can bark(). Hence the compiler decides that the function call should be based on the reference type, rather than the instance type.
If you're sure about type of dog you can always do typecasting
Object dog = new Dog();
((Dog)dog).bark();
Safe version:
Object dog = new Dog();
if (dog instanceof Dog)
((Dog)dog).bark();
UPD
Polymorphism example:
interface Animal {
}
interface Barkable extends Animal {
void bark();
}
class Dog implements Barkable {
#Override
public void bark() {
System.out.println("woof-woof");
}
}
class Cat implements Barkable {
#Override
public void bark() {
System.out.println("meow");
}
}
class SilentCreature implements Animal {
}
....
Animal animal = new Dog();
animal.bark();
animal = new Cat();
animal.bark();
animal = new SilentCreature();
// new SilentCreature() returns new animal, but not Barkable
animal.bark(); // as Animal doesn't have method bark() this code won't compile

casting a subclass object as superclass

I have some question about upcast/downcast.
I created an abstract super class Animal, subclass Dog and subclass BigDog. and I also give abstract method in Animal, and override it in Dog and BigDog.
abstract public class Animal {
abstract public void greeting();
}
public class Dog extends Animal {
#Override
public void greeting() {
System.out.println("Woof!");
}
}
public class BigDog extends Dog {
#Override
public void greeting() {
System.out.println("Woow!");
}
}
now my test code:
public class TestAnimal {
public static void main(String[] args) {
Animal animal2 = new Dog();
Animal animal3 = new BigDog();
// Downcast
Dog dog2 = (Dog) animal2; //cast Animal class to Dog class, legit
BigDog bigDog2 = (BigDog) animal3; //cast Animal to BigDog, legit;
Dog dog3 = (Dog) animal3; //Animal Class contains BigDog cast into Dog?
dog2.greeting();
dog3.greeting(); //in which class the method is called?
}
}
I understand the relationship between superclass/subclass and how cast works. My question is, however, can you cast a superclass into a specific subclass, knowing there's a class in between? for example, if I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?
in short, you can certainly say a superclass object is a subclass object, but why can you invert?
On second thought,
I'm guessing this: I'm asking JVM cast an Animal class reference to Dog and link the new Dog reference to the BigDog object, rather than really casting the BigDog object.
So I can invoke all Dog and Animal methods on that Dog reference (to BigDog), but none of the BigDog methods, unless it was overridden in BigDog.
What Java checks when invoking a method is: if the reference (DOG) has the reference, and if the object(BigDog) has an override. if not, Dog method is called, otherwise, BigDog method is called.
Can anyone confirm my guess?
You can always cast to a specific subclass, unless the compiler is smart enough to know for certain that your cast is impossible.
The best way to cast to a subclass is to check if it can be done:
if ( doggy instanceof BigDog ) {
doSomethingWithBigdog( (BigDog) doggy );
} else if ( doggy instanceof SmallDog ) {
doSomethingWithSmalldog( (SmallDog) doggy );
} else {
// Neither a big dog nor a small dog
}
...
private void doSomethingWithBigdog( BigDog dog ) {
...
}
private void doSomethingWithSmalldog( SmallDog dog ) {
...
}
Keep in mind that casting is evil. Sometimes necessary, but often (not always) it can be designed away by implementing methods on the base class, or by not assigning a Dog to an Animal variable but to keep it a Dog.
If I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?.
Simply you will get compiler error.Since you can't call a method that is not declared in parent and declared in child class using parent reference
There is no method whose signature will match with these method calls :
dog2.greeting(dog3);
dog3.greeting(dog2);
so, Its pretty much a compilation failure.
You need to know about Dynamic Method Dispatch.
here are few links 1,2,3 go through them.
First correct the source code, so it will compile. The proper usage of the methods: dog2.greeting(); and dog3.greeting(); or add method public void greeting(Animal animal);.
dog3.greeting(); - invoking method greeting() for dog3. dog3 has the same reference as animal3. animal3 has reference of BigDog so method greeting() is invoked to the class BigDog and the output is Woow!
When you inherit Dog from class Animal, then class Dog have all methods from class Animal.

Categories

Resources