Closed darrenangwx closed 1 year ago
I thnk that foo()
will only work if the underlying object passed into the function is a class DomesticCat
.
If line 5-7 is removed, then both Cat and Domestic Cat will work.
This is because during runtime, when an object is being casted, Java will look at the underlying object (not its label, the LHS identifier) and see if the underlying object can fit into the casted class type.
If the underlying object cannot be 'matched' to the casted class, it will throw a ClassCastException
.
'Matching' here works only when the underlying object is a Subclass (or the class itself) of the casted class.
For example:
// animal is labelled as an Animal, but the underlying object is a DomesticCat on heap memory
Animal animal = new DomesticCat();
// The downcasting works because the underlying object
// is a Domestic Cat even though it was labelled as an Animal
DomesticCat domestic = (DomesticCat) animal;
// This works too due to similar reasoning
Cat cat = (Cat) animal;
In the context of the code snippet given, this is a minimally reproducible piece of code you can try playing around with! (Tested on an online playground)
class Animal{
void speak(){
System.out.println("I'm an animal");
}
}
class Cat extends Animal{
@Override
void speak() {
System.out.println("I'm a Cat");
}
}
class DomesticCat extends Cat{
@Override
void speak() {
System.out.println("I'm a DomesticCat");
}
void catchMice(){
System.out.println("I caught a mouse!");
}
}
public class Main {
public static void foo(Animal a){
a.speak();
Cat c = (Cat)a; // downcast a to a Cat
c.speak();
DomesticCat dc = (DomesticCat)a; // downcast a to a DomesticCat
dc.speak();
dc.catchMice();
}
public static void main(String[] args) {
Animal animal = new Animal();
// foo(animal); // error
Cat cat = new Cat();
// foo(cat); // error
Cat cat1 = new DomesticCat();
foo(cat1); // OK
System.out.println("-------------");
Animal stillACat = (Animal) cat1;
foo(stillACat); // OK
}
}
If you wish to keep the current implementation of foo()
while avoiding ClassCastException
, you could also consider checking whether the underlying object is what you expect using instanceof
.
Here's an example you can consider:
public static void foo(Animal a) {
a.speak();
if (a instanceof Cat) {
Cat c = (Cat) a; // downcast a to a Cat
c.speak();
}
if (a instanceof DomesticCat) {
DomesticCat dc = (DomesticCat) a; // downcast a to a DomesticCat
dc.speak();
dc.catchMice();
}
}
Regarding![image](https://user-images.githubusercontent.com/15652564/216757109-eefecb3b-b045-45c2-94cc-6e5ea52b8b81.png)
Cat c = (Cat)a
infoo
method, does it only work ifa
is set asAnimal a = new DomesticCat();
orAnimal a = new Cat();
?