I have the following code in which I have a parent class and its child. I am trying to determine how the code benefits from using polymorphism.
class FlyingMachines {
public void fly() {
System.out.println("No implementation");
}
}
class Jet extends FlyingMachines {
public void fly() {
System.out.println("Start, Taxi, Fly");
}
public void bombardment() {
System.out.println("Throw Missile");
}
}
public class PolymorphicTest {
public static void main(String[] args) {
FlyingMachines flm = new Jet();
flm.fly();
Jet j = new Jet();
j.bombardment();
j.fly();
}
}
What is the advantage of polymorphism when both flm.fly() and j.fly() give me the same answer?
In your example, the use of polymorphism isn't incredibly helpful since you only have one subclass of FlyingMachine. Polymorphism becomes helpful if you have multiple kinds of FlyingMachine. Then you could have a method that accepts any kind of FlyingMachine and uses its fly() method. An example might be testMaxAltitude(FlyingMachine).
Another feature that is only available with polymorphism is the ability to have a List<FlyingMachine> and use it to store Jet, Kite, or VerySmallPebbles.
One of the best cases one can make for using polymorphism is the ability to refer to interfaces rather than implementations.
For example, it's better to have a method that returns as List<FlyingMachine> rather than an ArrayList<FlyingMachine>. That way, I can change my implementation within the method to a LinkedList or a Stack without breaking any code that uses my method.
What is the advantage of polymorphism when both flm.fly() and j.fly()
give me the same answer?
The advantage is that
FlyingMachines flm = new Jet();
flm.fly();
returns
"Start, Taxi, Fly"
instead of
"No implementation"
That's polymorphism. You call fly() on an object of type FlyingMachine and it still knows that it is in fact a Jet and calls the appropriate fly() method instead of the wrong one which outputs "No implementation".
That means you can write methods that work with objects of type FlyingMachine and feed it with all kinds of subtypes like Jet or Helicopter and those methods will always do the right thing, i.e. calling the fly() method of the appropriate type instead of always doing the same thing, i.e. outputting "No implementation".
Polymorphism
Polymorphism is not useful in your example.
a) It gets useful when you have different types of objects and can write classes that can work with all those different types because they all adhere to the same API.
b) It also gets useful when you can add new FlyingMachines to your application without changing any of the existing logic.
a) and b) are two sides of the same coin.
Let me show how.
Code example
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class PolymorphismDemo {
public static void main(String[] args) {
List<FlyingMachine> machines = new ArrayList<FlyingMachine>();
machines.add(new FlyingMachine());
machines.add(new Jet());
machines.add(new Helicopter());
machines.add(new Jet());
new MakeThingsFly().letTheMachinesFly(machines);
}
}
class MakeThingsFly {
public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
for (FlyingMachine flyingMachine : flyingMachines) {
flyingMachine.fly();
}
}
}
class FlyingMachine {
public void fly() {
out.println("No implementation");
}
}
class Jet extends FlyingMachine {
#Override
public void fly() {
out.println("Start, taxi, fly");
}
public void bombardment() {
out.println("Fire missile");
}
}
class Helicopter extends FlyingMachine {
#Override
public void fly() {
out.println("Start vertically, hover, fly");
}
}
Explanation
a) The MakeThingsFly class can work with everything that is of type FlyingMachine.
b) The method letTheMachinesFly also works without any change (!) when you add a new class, for example PropellerPlane:
public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
for (FlyingMachine flyingMachine : flyingMachines) {
flyingMachine.fly();
}
}
}
That's the power of polymorphism. You can implement the open-closed-principle with it.
The reason why you use polymorphism is when you build generic frameworks that take a whole bunch of different objects with the same interface. When you create a new type of object, you don't need to change the framework to accommodate the new object type, as long as it follows the "rules" of the object.
So in your case, a more useful example is creating an object type "Airport" that accepts different types of FlyingMachines. The Airport will define a "AllowPlaneToLand" function, similar to:
//pseudocode
void AllowPlaneToLand(FlyingMachine fm)
{
fm.LandPlane();
}
As long as each type of FlyingMachine defines a proper LandPlane method, it can land itself properly. The Airport doesn't need to know anything about the FlyingMachine, except that to land the plane, it needs to invoke LandPlane on the FlyingMachine. So the Airport no longer needs to change, and can continue to accept new types of FlyingMachines, be it a handglider, a UFO, a parachute, etc.
So polymorphism is useful for the frameworks that are built around these objects, that can generically access these methods without having to change.
let's look at OO design first, inheritance represents a IS-A relationship, generally we can say something like "let our FlyingMachines fly". every specific FlyingMachines (sub class) IS-A FlyingMachines (parent class), let say Jet, fits this "let our FlyingMachines fly", while we want this flying actually be the fly function of the specific one (sub class), that's polymorphism take over.
so we do things in abstract way, oriented interfaces and base class, do not actually depend on detail implementation, polymorphism will do the right thing!
Polymorphism (both runtime and compile time) is necessary in Java for quite a few reasons.
Method overriding is a run time polymorphism and overloading is compile time polymorphism.
Few of them are(some of them are already discussed):
Collections: Suppose you have multiple type of flying machines and you want to have them all in a single collection. You can just define a list of type FlyingMachines and add them all.
List<FlyingMachine> fmList = new ArrayList<>();
fmList.add(new new JetPlaneExtendingFlyingMachine());
fmList.add(new PassengerPlanePlaneExtendingFlyingMachine());
The above can be done only by polymorphism. Otherwise you would have to maintain two separate lists.
Caste one type to another : Declare the objects like :
FlyingMachine fm1 = new JetPlaneExtendingFlyingMachine();
FlyingMachine fm2 = new PassengerPlanePlaneExtendingFlyingMachine();
fm1 = fm2; //can be done
Overloading: Not related with the code you gave, But overloading is also another type of polymorphism called compile time polymorphism.
Can have a single method which accepts type FlyingMachine handle all types i.e. subclasses of FlyingMachine. Can only be achieved with Polymorphism.
It doesn't add much if you are going to have just Jets, the advantage will come when you have different FlyingMachines, e.g. Aeroplane
Now that you've modified to include more classes, the advantage of polymorphism is that abstraction from what the specific type (and business concept) of the instance you receive, you just care that it can fly
Polymorphism can also help our code to remove the "if" conditionals which is intended to produce production level code because removing conditionals will increase the code readability and helps us to write better unit test cases, we know for "n" if cases there comes n!(n factorial) possibilities.
Let us see how
if you have class FlyingMachine and which takes a string in the constructor defining the type of FlyMachine as below
class FlyingMachine{
private type;
public FlyingMachine(String type){
this.type = type;
}
public int getFlyingSpeedInMph {
if(type.equals("Jet"))
return 600;
if(type.equals("AirPlane"))
return 300;
}
}
We can create two instances of FlyingMachine as
FlyingMachine jet = new FlyingMachine("Jet");
FlyingMachine airPlane = new FlyingMachine("AirPlane");
and get the speeds using
jet.fylingSpeedInMph();
airPlane.flyingSpeedInMph();
But if you use polymorphism you are going to remove the if conditions by extending the generic FlyMachine class and overriding the getFlyingSpeedInMph as below
class interface FlyingMachine {
public int abstract getFlyingSpeedInMph;
}
class Jet extends FlyingMachine {
#Override
public int getFlyingSpeedInMph(){
return 600;
}
}
class Airplane extends FlyingMachine {
#Override
public int getFlyingSpeedInMph(){
return 600;
}
}
Now you can get the flying speeds as below
FlyingMachine jet = new Jet();
jet.flyingSpeed();
FlyingMachine airPlane = new AirPlane();
airPlane.flyingSpeed();
Both flm.fly() and j.fly() give you the same answer because of the type of the instance is actually the same, which is Jet, so they are behave the same.
You can see the difference when you:
FlyingMachines flm = new FlyingMachines();
flm.fly();
Jet j = new Jet();
j.bombarment();
j.fly();
Polymorphism is define as same method signature with difference behaviour. As you can see, both FlyingMachines and Jet have method fly() defined, but the method is implemented differently, which consider as behave differently.
See
aa
Polymorphism
Let's add one more class in this, It help's you to understand use of polymorphism..
class FlyingMachines {
public void fly() {
System.out.println("No implementation");
}
}
class Jet extends FlyingMachines {
public void fly() {
System.out.println("Start, Jet, Fly");
}
}
class FighterPlan extends FlyingMachines {
public void fly() {
System.out.println("Start, Fighter, Fight");
}
}
public class PolymorphicTest {
public static void main(String[] args) {
FlyingMachines flm = new Jet();
flm.fly();
FlyingMachines flm2 = new FighterPlan();
flm2.fly();
}
}
Output:
Start, Jet, Fly
Start, Fighter, Fight
Polymorphism gives you benefits only if you need Polymorphism.
It's used when an entity of your conceptual project can be seen as the specialization of another entity.
The main idea is "specialization".
A great example stands in the so called Taxonomy,for example applied to living beings.
Dogs and Humans are both Mammals.
This means that, the class Mammals group all the entities that have some properties and behaviors in common.
Also, an ElectricCar and a DieselCar are a specialization of a Car.
So both have a isThereFuel() because when you drive a car you expect to know if there's fuel enough for driving it.
Another great concept is "expectation".
It's always a great idea to draw an ER (entity relationship) diagram of the domain of your software before starting it.
That's because your are forced to picture which kind of entities are gonna be created and, if you're able enough, you can save lot of code finding common behaviors between entities.
But saving code isn't the only benefit of a good project.
You might be interested in finding out the so called "software engineering" that it's a collection of techniques and concepts that allows you to write "clean code" (there's also a great book called "Clean code" that's widely suggested by pro-grammes).
The good reason for why Polymorphism is need in java is because the concept is extensively used in implementing inheritance.It plays an important role in allowing objects having different internal structures to share the same external interface.
polymorphism as stated clear by itself, a one which mapped for many.
java is a oops language so it have implementation for it by abstract, overloading and overriding
remember java would not have specification for run time polymorphism.
it have some best of example for it too.
public abstract class Human {
public abstract String getGender();
}
class Male extends Human
{
#Override
public String getGender() {
return "male";
}
}
class Female extends Human
{
#Override
public String getGender() {
return "female";
}
}
Overriding
redefine the behavior of base class.
for example i want to add a speed count int the existing functionality of move in my base Car.
Overloading
can have behavior with same name with different signature.
for example a particular president speaks clear an loud but another one speaks only loud.
Here, for this particular code, there is no need of polymorphism.
Let's understand why and when we need polymorphism.
Suppose there are different kinds of machines (like car, scooter, washing machine, electric motor, etc.) and we know that every machine starts and stops. But the logic to start and stop a machine is different for each machine. Here, every machine will have different implementations to start and stop. So, to provide different implementations we need polymorphism.
Here we can have a base class machine with start() and stop() as its methods and each machine type can extend this functionality and #Override these methods.
Related
Here is the example code:
public class Whatever
{
public static void main(String[] args)
{
LazyManufacturer manufacturer = new LazyManufacturer();
Porsche oldPorsche = new Porsche();
Porsche newPorsche = new Porsche();
manufacturer.updateCar(oldPorsche, newPorsche);
// for a car that I do not know the brand of, I would instantiate Car directly. So Car cannot be abstract
}
}
public class Car {
private String carCommonAttribute;
public void updateAccordingTo(Car car) {
carCommonAttribute = car.carCommonAttribute;
System.out.println("common updated");
}
}
public class Porsche extends Car {
private String porscheExclusiveAttribute;
public void updateAccordingTo(Porsche car) {
super.updateAccordingTo(car);
porscheExclusiveAttribute = car.porscheExclusiveAttribute;
System.out.println("porsche exclusive updated");
}
}
public class Garbage extends Car {
private String garbageAttribute;
// similar to Porsche
}
public class LazyManufacturer {
public <T extends Car> void updateCar(T oldCar, T newCar) {
oldCar.updateAccordingTo(newCar);
}
}
I know this is a bad example, but it is good enough for illustrating what I'm trying to achieve.
Right now the output is "common updated". I would like to see "porsche exclusive updated" as well.
I understand that at compile time, startCar(car) would see start method in Car class as the best fit as its signature perfectly matches what it is looking for. However, is there a way to get around that at runtime? At runtime, startCar would find a better fit for the start method because Porsche is a narrower type, isn't it?
What mark is saying is Change your Car -> start() method to start() instead of start(Car). This way you will be able to achieve what you intent to do.
Usually classes in same hierarchy should have exactly same method signatures so that they override the base class method ( only when behaviour needs to change, of course child classes can also have more methods). There is no need to pass the Car instance to the method, as the object always has access to itself. The passed parameter serves no purpose. For the driver, yes driver needs to have a car as input. Why does the car needs itself as input to call a method?
"At runtime, startCar would find a better fit for the start method because Porsche is a narrower type, isn't it?"
Isn't.
At runtime, JVM has no spare time to choose methods's best fit depending on actual type of given argument.
Best fit is chosen at compile time, according to declared type of arguments.
As #markspace said, you probably want to override start(), instead of overloading it. To do so, make signatures of Car.start() and Porche.start() identical. Either remove the argument (it is not used anyway), or declare the argument as Car car in both cases.
I have 2 classes that perform a very similar task, but require different data types passed to them in order to perform those functions.
They both ultimately write to files and have expose a single public method: write() using the constructor for simple dependency injection.
This is where they differ - 1 class accepts a single object of a specific type, while the other accepts an array of that object type.
Is this a valid case for polymorphism? I think it can be but tehcnically should not?
How is this situation to be correctly handled i.e. 2 or more classes which perform a very similar function, but in a slightly different way and crucially, require different data types passed in as dependencies?
You need overloaded methods in this case. One which works with single object and other with a number of objects. They should be in the same class.
Here is an easy-to-remember way of when to use what:
1. Overloading is when you need to do the same thing with different data
2. Overriding is when you need to do the same thing with the same data in a different way
public class FileWriter {
public void write(File from){ // single file
// magic logic
}
public void write(File... from){ // multiple files using varargs
// magic logic
}
}
If you only have two Write methods, one taking a single object and the other taking a List of objects -> I would put both methods on the same class.
If you have one Write for each type, I would go for generics.
Introducing a base class wouldn't be my first choice, better to extract the general stuff into another class and use it from different classes (has-a instead of is-a).
Polymorphism is only useful if you have the same method signature but need to do stuff in different ways.
Hard to answer without a particular code sample, but the scenario you've presented fits something similar to a decorator pattern:
class X
{
public void doSomething(int number) { ... }
};
class XForCollections
{
public XForCollections(X x) { ... }
public void doSomething(int[] numbers) { ... }
};
Note, that it's not really a decorator, as XForCollection doesn't inherit X.
Use an abstract generic superclass with the common stuff.
If you want WriterA that writes an argument of type ArgA, and WriterB that writes an argument of type ArgB, you'll make
an abstract Writer<T> with all of the common stuff in it, and an abstract method such as public void write(T arg)
WriterA that extends Writer<ArgA>
WriterB that extends Writer<ArgB>
Say you have this:
class A{
void write(int a){}
}
class B{
void write(int[] a){}
}
Since you say the implementations for those methods vary deeply between each other, then varargs probably wouldn't be a suitable option. To simplify things, do this::
class WriteStuff{
void write(int a){}
void write(int[] a){}
}
This would let you attain a higher level of cohesion for your classes. Polymorphism isn't really necessary here.
Then again, it's really too little information to go on with. You should probably write up some example code.
Polymorphism – means the ability of a single variable of a given type to be used to reference objects of
different types, and automatically call the method that is specific to the type of object the variable references. In a
nutshell, polymorphism is a bottom-up method call. The benefit of polymorphism is that it is very easy to add new
classes of derived objects without breaking the calling code that uses the polymorphic classes or interfaces. When you send a message to an object even though you
don’t know what specific type it is, and the right thing happens, that’s called polymorphism. The process used by
object-oriented programming languages to implement polymorphism is called dynamic binding.
Example:
Launcher
private void init() {
//client or calling code
double dim = 5.0; //i.e. 5 meters radius or width
List<Shape> listShapes = new ArrayList<Shape>(20);
Shape s = new Circle();
listShapes.add(s); //add circle
s = new Square();
listShapes.add(s); //add square
getTotArea (listShapes,dim); //returns 78.5+25.0=103.5
//Later on, if you decide to add a half circle then define
//a HalfCircle class, which extends Circle and then provide an
//area(). method but your called method getTotArea(...) remains
//same.
}
/** called method: method which adds up areas of various
** shapes supplied to it.
**/
public double getTotArea(List<Shape> listShapes, double dim){
Iterator<Shape> it = listShapes.iterator();
double totalArea = 0.0;
//loop through different shapes
while(it.hasNext()) {
Shape s = (Shape) it.next();
totalArea += s.area(dim); //polymorphic method call
}
return totalArea ;
}
}
Shape
public abstract class Shape {
protected abstract double area(double dim);
}
Square
public class Square extends Shape{
#Override
protected double area(double dim) {
return dim*dim;
}
}
Circle
public class Circle extends Shape{
#Override
protected double area(double dim) {
return Math.PI*dim*dim;
}
}
While working on a project, I was presented with a task to design a set of classes that implement an interface defining a simple action. Usually these classes would do their job in particular sequence, all at once, but the possibility to call a method from only one of them was also a requirement.
Taking into account all the above and also considering that:
- each class would have quite basic logic
- extending another class was not required
- it might be convenient to have all classes in a single file
- editing source file when needed is not an issue
I came up with the following solution (actual class was not so contrived, but the example below is sufficient to give you some basic idea):
public enum Bestiary {
DOG(1) {
#Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud("I am alpha dog");
}
},
CAT(2) {
#Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud("I am beta cat");
}
},
RAT(3) {
List<String> foods = new ArrayList<>();
{
foods.add("gods");
foods.add("dogs");
foods.add("cats");
foods.add("other rats");
}
#Override
void makeNoise(Loudspeaker ls) {
StringBuilder cry = new StringBuilder("I am THE rat; usually I eat ");
for (int i = 0; i < foods.size(); i++) {
cry.append(foods.get(i));
if (i != (foods.size() - 1)) {
cry.append(", ");
}
}
ls.shoutOutLoud(cry.toString());
}
},
THE_THING(4) {
String name = "r2d2";
#Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud(calculateHash(name));
}
private String calculateHash(String smth) {
return String.valueOf(smth.hashCode());
}
};
private int id;
public int getId() {
return id;
}
Bestiary(int id) {
this.id = id;
}
abstract void makeNoise(Loudspeaker ls); // all enum elements will need to implement this - kind of like implementing an interface (which was also an option); note that we pass some arbitrary object and call methods on it
}
And code which calls this class might look like:
public final class Loudspeaker {
private static Loudspeaker loudspeaker = new Loudspeaker();
public static void shoutOutLoud(String cry) {
System.out.println(cry);
}
static class Noizemakers {
public static void makeSomeNoise() {
for (Bestiary creature: Bestiary.values()) {
System.out.println(creature + " with id " + creature.getId() + " says: ");
creature.makeNoise(loudspeaker);
}
}
}
public static void main(String[] args) {
Noizemakers.makeSomeNoise();
Bestiary.CAT.makeNoise(loudspeaker);
}
}
During a code review my suggestion was mocked as the one that is "too hacky, exploites the fact that enums have class body and methods, and have a bad code smell in overall". While transforming it into a separate interface, a bunch of usual Java classes etc. is a matter of few minutes, I was not really quite satisfied with this explanation. Are there any guidelines saying that you should use enums exclusively in their basic form, similarly to other languages? What real drawbacks does this approach have? How about Joshua Bloch's suggestion to write singletons as enums - in this case such an enum will have to be a full-fledged class, right?
One could use an enum anywhere you have a shallow class hierarchy, with trade offs between extensibility (classes have more, enums have less) and conciseness (if the functionality is straightforward, enums are probably clearer). It's not the right thing to do all the time, but it's certainly ok to do some of the time, just be aware of the differences, some of which I list below.
To my mind, the situation you're dealing with seems to me to be exactly the kind of thing the language designers were working to support by allowing enums to have methods. It doesn't seem to me that you're subverting the intention of that language feature in the least.
As an example from my work, I often use enums with methods as a way of implementing a variety of stateless strategies, but have also used them for other things, including being a kind of extensible form of Class.
Answers to your specific questions:
What real drawbacks does this approach have?
Compared to the interface + concrete classes approach:
Methods defined in a specific enum value can't be called from outside that value. eg, if you defined a method for RAT called squeak(), no one can call it.
No mutable state, because each enum value is effectively a singleton.
Your enum class file can get excessively long if the number of types increases dramatically, or the code for each type increases.
Can't subclass enum values, they are effectively final
No doubt some others...
Are there any guidelines saying that you should use enums exclusively in their basic form, similarly to other languages?
None that I've ever seen.
How about Joshua Bloch's suggestion to write singletons as enums - in this case such an enum will have to be a full-fledged class, right?
Following the logic of your questioners, yes. So it becomes a question of whether you'd rather listen to them, or to Josh Bloch.
You should only use an enum where there is no (or little) possibility of the addition of a new element. This is not to say that you shouldn't give an enum class-like functions. For example:
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
}
There are multiple reasons for this:
Semantics/intended purpose. It just doesn't make sense to have enums for non-enumerations, by the very definition of the word.
Compatibility. What if I want to add a bird to your bestiary? You'd have to amend the enum. Easy enough, but what if you have some users using an older version of the enum and others using a later version? This makes for lots of compatibility issues.
One (suboptimal) solution if you must use an enum would be:
interface Animal {
void makeNoise();
}
enum Bestiary implements Animal {
// the rest of the stuff here
}
Then, any method currently accepting a Bestiary could be easily switched to accept an Animal. However, if you do this, it's better anyway to just have:
interface Animal {
void makeNoise();
}
public class Dog implements Animal {...}
public class Cat implements Animal {...}
public class Rat implements Animal {...}
public class Thing implements Animal {...}
My personal opinion is that enums should not contain any mutating methods, as it violates most assumptions of enumerated values having constant state. ...But looking over your work again, that does not actually appear to be the case. It certainly seems odd to do it this way, but it's more of an "unexpected usage" thing than specifically being a "wrong way to do it" thing.
Just make sure that any potentially-modifiable values within the enumerated types aren't accessible externally, such as foods. (The Strings can be made final, so that's not an issue, but making foods final wouldn't prevent people from manipulating the list itself, just assigning a new one.)
See the following example:
interface I {}
class A implements I {}
class B implements I {}
class Foo{
void f(A a) {}
void f(B b) {}
static public void main(String[]args ) {
I[] elements = new I[] {new A(), new B(), new B(), new A()};
Foo o = new Foo();
for (I element:elements)
o.f(element);//won't compile
}
}
Why doesn't overloading methods support upcasting?
If overloading was implemented at run time, it would provide much more flexibility. E.g, the Visitor Pattern would be simpler. Is there any technical reason that prevents Java from doing this?
Overload resolution involves some non-trivial rules to determine which overload is the best fit, and it'd be hard to do these efficiently at runtime. In contrast, override resolution is easier -- in the hard case you have to just look up the foo function for the object's class, and in the easy case (e.g. when there's only one implementation, or only one implementation in this code path), you can turn the virtual method into a statically-compiled, non-virtual, non-dynamically-dispatching call (if you're doing it based on the code path, you have to do a quick check to verify that the object is actually the one you expect).
As it turns out, it's a good thing Java 1.4 and lower didn't have runtime override resolution, because that would make generics much harder to retrofit. Generics play a role in override resolution, but this information wouldn't be available at runtime due to erasure.
There is no theoretical reason why it cannot be done. The Common Lisp Object System supports this type of construction — called multiple dispatch — although it does so in a somewhat different paradigm (methods, rather than being attached to objects, are instances of generics (or generic functions), which can do virtual dispatch at run-time on the values of multiple parameters). I believe there have also been extensions to Java to enable it (Multi-Java comes to mind, although that may have been multiple inheritance rather than multiple dispatch).
There may, however, be Java language reasons why it cannot be done, besides the language designers just thinking it shouldn't be done, that I'll leave others to reason about. It does introduce complications for inheritance, though. Consider:
interface A {}
interface B {}
class C implements A {}
class Foo {
public void invoke(A a) {}
public void invoke(B b) {}
}
class Bar extends Foo {
public void invoke(C c) {}
}
class Baz extends Bar {
public void invoke(A a) {}
}
Baz obj = new Baz();
obj.invoke(new C);
Which invoke is invoked? Baz? Bar? What is super.invoke? It is possible to come up with deterministic semantics, but they will likely involve confusion and surprise in at least some cases. Given that Java aims to be a simple language, I don't think features introducing such confusion are likely to be seen as according with its goals.
Is there any technical reason that prevents Java from doing this?
Code correctness: your current example provides two implementations of I and two corresponding methods f. However nothing prevents the existence of other classes implementing I - moving the resolution to runtime would also replace compile errors to possibly hidden runtime errors.
Performance: as others have mentioned method overloading involves rather complex rules, doing so once at compile time is certainly faster than doing it for every method invocation at runtime.
Backwards compatibility: currently overloaded methods are resolved using the compile time type of passed arguments rather than their runtime type, changing the behavior to use runtime information would break a lot of existing applications.
How to work around it
Use the visitor pattern, I do not understand how someone would think that it is hard.
interface I{
void accept(IVisitor v);
}
interface IVisitor{
void f(A a);
void f(B b);
}
class A implements I{
void accept(IVisitor v){v.f(this);}
}
class B implements I{
void accept(IVisitor v){v.f(this);}
}
class Foo implements IVisitor{
void f(A a) {}
void f(B b) {}
static public void main(String[]args ) {
I[] elements = new I[] {new A(), new B(), new B(), new A()};
Foo o = new Foo();
for (I element:elements)
element.accept(o);
}
}
I don't think anyone but the designers of the language could possible answer this question. I am not nearly an expert on the subject, but I will provide just my opinion.
By reading the JLS 15.12 about Method Invocation Expressions, it is pretty clear that choosing the right method to execute is an already complicated compile-time process; above all after the introduction of generics.
Now imagine moving all this to the runtime just to support the single feature of mutimethods. To me it sounds like a small feature that adds too much complexity to the language, and probably a feature with certain amount of performance implications now that all these decisions would need to be made, over and over, at runtime, and not just once, as today it is, at compile time.
To all these we could add the fact that due to type erasure it would be impossible to determine the actual type of certain generic types. It appears to me that abandoning the safety of the static type checking is not in the best interest of Java.
At any rate, there are valid alternatives to deal with the multiple dispatch problem, and perhaps these alternatives pretty much justify why it has not been implemented in the language. So, you can use the classical visitor pattern or you can use certain amount of reflection.
There is an outdated MultiJava Project that implemented mutiple dispatch support in Java and there are a couple of other projects out there using reflection to support multimethods in Java: Java Multimethods, Java Multimethods Framework. Perhaps there are even more.
You could also consider an alternative Java-based language which does support multimethods, like Clojure or Groovy.
Also, since C# is a language pretty similar to Java in its general phillosopy, it might be interesting to investigate more on how it supports multimethods and meditate on what would be the implications of offering a similar feature in Java. If you think it's a feature worth having in Java you can even submit a JEP and it may be taken into account for future releases of the Java language.
Not the answer to Java. This functionality exists in C# 4 though:
using System;
public class MainClass {
public static void Main() {
IAsset[] xx = {
new Asset(), new House(), new Asset(), new House(), new Car()
};
foreach(IAsset x in xx) {
Foo((dynamic)x);
}
}
public static void Foo(Asset a) {
Console.WriteLine("Asset");
}
public static void Foo(House h) {
Console.WriteLine("House");
}
public static void Foo(Car c) {
Console.WriteLine("Car");
}
}
public interface IAsset { }
public class Asset : IAsset { }
public class House : Asset { }
public class Car : Asset { }
Output:
Asset
House
Asset
House
Car
If you are using C# 3 and below, you have to use reflection, I made a post about it on my blog Multiple Dispatch in C# : http://www.ienablemuch.com/2012/04/multiple-dispatch-in-c.html
If you want to do multiple dispatch in Java, you might go the reflection route.
Here's another solution for Java: http://blog.efftinge.de/2010/03/multiple-dispatch-and-poor-mens-patter.html
Guess you just have to settle with reflection:
import java.lang.reflect.*;
interface I {}
class A implements I {}
class B implements I {}
public class Foo {
public void f(A a) { System.out.println("from A"); }
public void f(B b) { System.out.println("from B"); }
static public void main(String[]args ) throws InvocationTargetException
, NoSuchMethodException, IllegalAccessException
{
I[] elements = new I[] {new A(), new B(), new B(), new A()};
Foo o = new Foo();
for (I element : elements) {
o.multiDispatch(element);
}
}
void multiDispatch(I x) throws NoSuchMethodException
, InvocationTargetException, IllegalAccessException
{
Class cls = this.getClass();
Class[] parameterTypes = { x.getClass() };
Object[] arguments = { x };
Method fMethod = cls.getMethod("f", parameterTypes);
fMethod.invoke(this,arguments);
}
}
Output:
from A
from B
from B
from A
Your method says it will accept A or B which are derived classes of I, they can contain more details then I
void f(A a) {}
When you try to send super class of A in your case interface I, compiler wants a confirmation that you are actually sending A as details available in A may not be available in I, also only during runtime I will actually refer to an instance of A no such information available at compile time, so you will have to explicitly tell the compiler that I is actually A or B and you do a cast to say so.
Take a look at this code (from here)
abstract class EntityA {
AssocA myA;
abstract void meet();
}
abstract class AssocA {
int something;
abstract void greet();
}
class AssocAConcrete extends AssocA {
void greet() {
System.out.println("hello");
}
void salute() {
System.out.println("I am saluting.")
}
}
class EntityAConcrete extends EntityA {
void meet() {
System.out.println("I am about to meet someone");
((AssocAConcrete)myA).salute();
}
}
There are two parallel inheritance trees, for a parent class and an associated class. The problem is with line 23:
((AssocAConcrete)myA).salute();
It is a pain and I have that kind of thing all over my code. Even though that line is part of the concrete implementation of Entity, I need to remind it that I want to use the concrete implementation of AssocA, AssocAConcrete.
Is there some kind of annotation to declare that relationship? Or is there a better, more colloquial Java way to express this design? Thanks!
This is in response to #Dave, because I want to put some code in...
Interesting! So the invocation would look something like this:
AssocAConcrete myAssoc = new Assoca();
EnitityA<T extends AssocA> myEntity = new EntityA<AssocAConcrete>();
myEntity.setAssoc(myAssoc);
myAssoc.salute();
Yes? That's really cool. I think I will use it!
I would think this is a lot neater using generics...
abstract class EntityA<T extends AssocA> {
// Basically, this means myA is at least an AssocA but possibly more...
T myA;
abstract void meet();
}
abstract class AssocA {
int something;
abstract void greet();
}
class AssocAConcrete extends AssocA {
void greet() {
System.out.println("hello");
}
void salute() {
System.out.println("I am saluting.");
}
}
class EntityAConcrete extends EntityA<AssocAConcrete> {
void meet() {
System.out.println("I am about to meet someone");
myA.salute();
}
}
Aside from avoiding the casting, this also makes it much easier to add different functionality in your AssocA implementations. There should always be a way to do things without using dummy implementations (ie methods that just throw "NotImplementedException") or casting. Even though it isn't always easy or worth the refactoring time to do so. In other words, no one is going to blame you for casting (well...maybe some people will but you can't please everyone).
EDIT (Notes on instantiation):
From #pitosalas' comments below...
//Won't work...can't call 'new' on abstract class AssocA
AssocAConcrete myAssoc = new Assoca();
//Instead, do this...
AssocAConcrete myAssoc = new AssocAConcrete();
And then....
// Again, won't work. T is only declaring the type inside your class/method.
// When using it to declare a variable, you have to say EXACTLY what you're making,
// or at least something as exact as the methods you're trying to invoke
EnitityA<T extends AssocA> myEntity = new EntityA<AssocAConcrete>();
//Instead do this...
EnitityA<AssocAConcrete> myEntity = new EntityAConcrete();
// Or this...
EntityAConcrete myEntity = new EntityAConcrete();
And then this should be good...
// Assuming this is defined as `public void setAssoc(T newAssoc) {this.myA = newAssoc;}`
myEntity.setAssoc(myAssoc);
myAssoc.salute();
Looks suspicious to me. There is nothing terrible about casting, but in this case, you could resolve the issue by bringing the salute method into AssocA. Subclasses of AssocA can provide their implementations; that's part of the benefit of inheritance.
What you are doing now is saying all EntityA instances have an AssocA instance, but then in your meet method you basically force the AssocA instance to be an AssocAConcrete instance. That's the part that is suspicious; why does AssocA exist if you really need an AssocAConcrete.
Another option (based on your comments) is to invoke salute in the greet method. That way, the specific subclass has specified behavior greet, defined in the superclass, and does what it wants. In this case, salute could become private or protected. Another implementation can easily do something different, like runLikeHell.
The problem of parallel class hierarchies is very real and really sucks. The logical coupling that AssocAConcrete always go with EntityAConcrete can not be expressed with the type system.
You can not specialize the type of myA in EntityAConcrete to be AssocAConcrete, without hiding it from a superclass. I think the closest work that addressed that was "Family polymorphism", but that's not mainstream.
If you have a large part of code where you are using the reference "myA" you could declare another reference like that:
public AssocAConcrete myAConcrete = (AssocAConcrete)myA;
now you can use the new reference myAConcrete and access the functions of the AssocAConcrete Class.
If you need to do this a lot like hvgotcodes mentioned you should probbably consider moving the method up to the AssocA Class.