1
class Animal{
  public void findAnimal(){
    System.out.println("Animal class");
  }
  public void sayBye(){
    System.out.println("Good bye");
  }
}

class Dog extends Animal{
 public void findAnimal(){
  System.out.println("Dog class");
 }
}

Given the inheritance above ,it is understood that a reference of Animal can refer to an object of Dog

Animal animal=new Dog();

As a Dog object can perform everything an Animal can do like in above case a Dog also have sayBye and findAnimal methods.

But why it is allowed to downcast an Animal object to a Dog object which serves no purpose and fails at runtime.

Dog dog=(Dog)new Animal(); // fails at runtime but complies.

Dog dog=(Dog)animal;

The above statement look logical as the animal reference is pointing to a Dog object.

Pankaj
  • 14,638
  • 3
  • 17
  • 23
  • 3
    You're claiming that `Dog dog=(Animal)new Animal();` compiles? – Kayaman Jun 05 '15 at 06:32
  • 3
    It is syntactically and semantically correct: just like x=1/0 – cup Jun 05 '15 at 06:35
  • @Kayaman : my bad it should be Dog dog=(Dog) new Animal(); – Pankaj Jun 05 '15 at 06:35
  • 2
    JLS specifies exact rules when compile time errors occur : https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1, Refer: If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs – Nitin Dandriyal Jun 05 '15 at 06:59

5 Answers5

6

This sort of casting is allowed for situations when you get an object of a superclass from outside code, e.g. as a parameter to your method, and then you need to call methods specific to a subclass.

This is not a good practice, but in some rare situations you are forced to do things like that, so the language allows it:

void sound(Animal animal) {
    if (animal instanceof Dog) {
        Dog dog = (Dog)animal();
        dog.bark();
    }
    if (animal instanceof Cat) {
        Cat cat = (Cat)animal();
        cat.meow();
    }
}

why it is allowed to compile Dog dog=(Dog) new Animal()

Because compiler designers decided to not detect this error at compile time. They verified that the expression being cast to Dog is of type that is a superclass of Dog, and allowed the expression to compile. They could go further and check that the expression will always result in an exception, but that would require an additional effort for very little improvement in user experience with the language.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I agree to this if an "animal" reference is pointing to a Dog object it should be type cast back to Dog . But why it is allowed to compile Dog dog=(Dog) new Animal(). Further it fails at runtime even if we do not use the reference dog. – Pankaj Jun 05 '15 at 06:40
  • @Neeraj has pointed to the JLS that explains why the given cast is allowed at compile time. After that it is pure guesswork. Unless one is the actual designer and implementor of the casting functionality, there is no way to claim that there was a conscious decision not to implement the indicated functionality. The best we can guess is that the compiler is happy to examine the types on the two sides of the casting operator and applying the language specification to the two types discovered. Why the compiler does not try harder to detect clear violations could be due to any number of reasons. – manish Jun 05 '15 at 07:15
4

Because you need it sometimes.

Especially when Java did not yet have generics (Java 1.4 and older), you almost always needed to cast when you got for example an object out of a collection.

// No generics, you don't know what kinds of objects are in this list
List list = new ArrayList();

list.add(new Dog());

// Need to cast because the return type of list.get() is Object
Dog dog = (Dog)list.get(0);

Since we have generics since Java 5, the need for casting is greatly reduced.

You should try to avoid casting in your code as much as possible. A cast is a way to deliberately switch off the compiler's type checking - in general you don't want to do that, you want to make use of the compiler's checking instead of circumventing it. So, if you have code where you need to cast, think a bit further to see if you can write it without the cast.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • Thanks Jesper . Here the object in the ArrayList are of type Dog. So it makes sense to cast them back to Dog from Object. My questing is why statement like Dog dog=(Dog) new Animal() is allowed. – Pankaj Jun 05 '15 at 06:46
  • @Pankaj The exact rules for what is and what is not allowed are described in [section 5.5.1 of the JLS](https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1). If types are unrelated, then the compiler will give you an error. But if the types are related (for example because `Animal` is a supertype of `Dog`), the compiler will allow the cast. – Jesper Jun 05 '15 at 07:07
1

You need that capability to access an earlier cast object as its original type.

For example, if you cast a Dog to an Animal to pass it to a generic processor, you may later need to cast it back to a Dog to perform specific methods.

The developer is responsible to make sure the type is compatible - and when it is there will be no error. Some pseudo code:

public void example(Animal foo){
    if( ...condition... ) ((Dog)foo).bark();
    else if( ...other condition... ) ((Cat)foo).meow();
}

Since the introduction of generics, this is less commonly used, but there are still cases for it. The developer is solely responsible for guaranteeing the type is right if you don't want an error.

Scott 'scm6079'
  • 1,517
  • 13
  • 25
0

case 1 -

Here we use loose coupling.

Animal animal = getSomeDog(),

Dog dog = (Dog) animal; // this is allowed because animal could reference a dog

case 2

Here we you use tight coupling.

Animal animal = new Animal();

Dog dog = (Dog) animal; // this will fail at runtime, because animal doesn't reference a Dog

We use Downcasting when there is possibility to succeed at run time so case 1 has possibility to succeed at runtime over case 2

Afgan
  • 1,022
  • 10
  • 32
0

Down casting is considered as a bad Object Oriented practice. It must be avoided to as much extent as possible.

Java still has it and your question is a good question as why Java allows Down-casting.

Suppose a case below.

public interface List{
    public boolean add(Object e);
    public boolean remove(Object o);
}  

public class ArrayList implements List{

  // Extra method present in the ArrayList and not in the parent Interface
    public Object[] toArray() {
        // returns array of the objects
        return Arrays.copyOf(elementData, size);
    }

    @Override
    public boolean add(Object e){
        // add e to the ArrayList Underlying array
    }
    @Override
    public boolean remove(Object o){
       // remove o from the ArrayList Underlying array
    }
}

A good Object oriented practice is to Code for Interfaces. But often there are methods defined in the concrete implementations which we need to call. I read an comment from some one and I quote it in my words.

Know the Rules, in case you need to break them Do break them Knowingly and take care so as to prevent from any adverse effect.

Below is an example where we need to do the Down-casting. The example of down-casting in your question is to teach what is down-casting, below is real life example.

public void processList(List items){
   items.add( new Object() );
   items.add( new Object() );
   processAsPerTypeOfList(items);
}

public void processAsPerTypeOfList( List items ){
    if( items instanceof ArrayList){
         Object[] itemArray = ((ArrayList)items).toArray();// DOWNCASTING
         // Process itemArray
    }
} 

For more reference you can also see a related question : Why Java needs explicit downcasting?

Community
  • 1
  • 1
nits.kk
  • 5,204
  • 4
  • 33
  • 55