Java Best Practices: Casting Objects Against Interfaces

Suppose we have the following toy interfaces:

interface Speakable { public abstract void Speak(); } interface Flyer { public abstract void Fly(); } 

and we have a class that implements both interfaces:

 class Duck implements Speakable, Flyer { public void Speak() { System.out.println("quack quack don't eat me I taste bad."); } public void Fly() { System.out.println("I am flying"); } } 

At this moment, I see different ways to call methods on Duck , and I can’t decide which one works best. Consider this scenario:

 public class Lab { private static void DangerousSpeakAndFly(Object x) { Speakable temp = (Speakable) x; temp.Speak(); Flyer temp2= (Flyer) x; temp2.Fly(); } public static void main(String[] args) { Duck daffy= new Duck(); DangerousSpeakAndFly(daffy); } } 

This program will behave as expected, because the object passed to the function can be hidden before Flyer and Speakable , but I compress when I see such code, because it does not allow checking the type of compilation time and because of the hard link, it may cause unexpected exceptions, for example, when an object with a different typification is passed as a parameter (not movable to any of the interfaces), or if the Duck implementation modifies the string so that it no longer implements Flyer .

I see Java code written this way all the time, sometimes in textbooks (for example, p. 300 of “Head First Design Patterns” O'Reilly), so there should be something in it that I am missing.

If I wrote similar code, I would try to avoid downcasting to a type or interface that is not guaranteed. for example, in this case, I would do something like this:

 interface SpeakingFlyer extends Flyer, Speakable { } class BuzzLightyear implements SpeakingFlyer { public void Speak() { System.out.println("My name is Buzz"); } public void Fly() { System.out.println("To infinity and beyond!"); } } 

What will allow me to do:

 private static void SafeSpeakAndFly(SpeakingFlyer x) { x.Speak(); x.Fly(); } public static void main(String[] args) { BuzzLightyear bly= new BuzzLightyear(); SafeSpeakAndFly(bly); } 

Is this too much? What are the pitfalls for this?

It seems to me that this construction separates the SafeSpeakAndFly() function from its parameters and prevents unpleasant errors due to checking the type of compilation time.

Why is the first method widely used in practice and the second not?

+7
java inheritance casting oop downcasting
source share
2 answers

I see Java code written this way all the time, sometimes in textbooks (for example, p. 300 of “Head First Design Patterns” O'Reilly), so there should be something in it that I am missing.

This book was originally published back in 2004, and I don't think that Java supported Generics at that time. Thus, unsafe casting was what was often used then. Perhaps if I didn’t have support for parametric polymorphism in Java, I would first check if this parameter is an instance of the type that I would like to discard, and then perform the actual selection:

 private static void dangerousSpeakAndFly(Object x) { if (x instanceof Speakable) { Speakable temp = (Speakable) x; temp.Speak(); } if (x instanceof Flyer) { Flyer temp2= (Flyer) x; temp2.Fly(); } } 

With Generics, we can do this:

 private static <T extends Speakable & Flyer> void reallySafeSpeakAndFly(T x) { x.Speak(); x.Fly(); } 

Here, the compiler can make sure that we are not transmitting something that does not implement Speakable and Flyer , and can detect such sassy attempts at compile time.

Why is the first method widely used in practice and the second not?

You may have seen a lot of legacy code, I suppose. :)

+11
source share

You can apply the argument at the same time to Speakable and Flyer , creating a method that is common with type intersection:

 private <T extends Speakable & Flyer> static void DangerousSpeakAndFly(T x) { // use any of `Speakable` or `Flyer` methods of `x` } 

this way, you do not need casting or creating an additional interface.

+7
source share

All Articles