Java: Is polymorphism only practical for methods with identical signatures? - java

The only examples of polymorphic method overriding I ever see involve methods that take no parameters, or at least have identical parameter lists. Consider the common Animal/Dog/Cat example:
public abstract class Animal
{
public abstract void makeSound();
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
}
}
In this case, everything works out just fine. Now let's add another method that gets partially implemented in the abstract class while getting the more specific behavior in the subclasses:
public abstract class Animal
{
public abstract void makeSound();
public void speak(String name)
{
System.out.println("My name is " + name);
}
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
public void speak(String name)
{
super.speak(name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
public void speak(String name, int lives)
{
super.speak(name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
// a.speak(NOW WHAT?
}
}
In that last (commented) line of the main method, I don't know what to put there because I don't know what type of Animal I have. I didn't have to worry about this before because makeSound() didn't take any arguments. But speak() does, and the arguments depend on the type of Animal.
I've read that some languages, such as Objective-C, allow for variable argument lists, so an issue like this should never arise. Is anyone aware of a good way to implement this kind of thing in Java?

You are confusing method overriding and method overloading. In your example the Cat class has two methods:
public void speak(String name) // It gets this from its super class
public void speak(String name, int lives)
Overloading is a way to define methods with similar functions but different parameters. There would be no difference if you had named the method thusly:
public void speakWithLives(String name, int lives)
To avoid confusion the recommendation in java is to use the #Override annotation when you are attempting to override a method. Therefore:
// Compiles
#Override
public void speak(String name)
// Doesn't compile - no overriding occurs!
#Override
public void speak(String name, int lives)
EDIT: Other answers mention this but I am repeating it for emphasis. Adding the new method made the Cat class no longer able to be represented as an Animal in all cases, thus removing the advantage of polymorphism. To make use of the new method you would need to downcast it to the Cat type:
Animal mightBeACat = ...
if(mightBeACat instanceof Cat) {
Cat definitelyACat = (Cat) mightBeACat;
definitelyACat.speak("Whiskers", 9);
} else {
// Definitely not a cat!
mightBeACat.speak("Fred");
}
The code inspection tool in my IDE puts a warning on the instanceof as the keyword indicates possible polymorphic abstraction failure.

Your example Cat isn't polymorphic anymore, since you have to know it's a Cat to pass that parameter. Even if Java allowed it, how would you use it?

As far as I know java doesn't allow you to do that. speak(name, lives) is now just the Cat's function. Some languages do allow this type of flexibility. To force java to allow this, you can make the paramater an array of objects or some other collection.
However, consider that when you call speak, you now must know which parameters to pass in regardless, so the point is somewhat moot.

When you call a polymorphic method as:
a.speak("Gerorge");
You don't need to know what type of Animal has instantiated because this is the objective of polymorphism. Also since you have user the sentence:
super.speak(name);
Both Cat an Dog will have the behavior of Animal plus the own behavior.

You can do
public void speak(Map ... mappedData)
{
System.out.println("My name is " + mappedData.get("name")+ " and I have "+mappedData.get("lives");
}
However, I would advise making lives an instance variable of Cat and have your factory pass a default value (or have the constructor have a default parameter for it).

In this case best way is to use a DTO,
public class SpeakDTO
{
//use getters and setters when you actually implement this
String name;
int lives;
}
public class Dog extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a cat and I have " + dto.lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
SpeakDTO dto = new SpeakDTO();
dto.name = "big cat";
dto.lives = 7;
a.speak(dto);
}
}

If you want to make a call like that, you could use reflection to get the class:
if (a.getclass() == Cat.class) {
// speak like a cat
} else if (a.getclass() == Dog.class) {
.
.
.
Of course this might not be the best design, and reflection should be used with care.

Java also has variable argument lists, but I'd argue that's not the "best" way to do it, at least not in all circumstances.
When subclasses have behavior that isn't defined by the interface, you don't have many options in Java that aren't verbose or a bit wonky.
You could have a speak () that takes a marker interface and delegate arg construction to a factory. You could pass a parameter map. You could use varargs.
Ultimately, you need to know what to pass to the method, no matter what language.

I agree with the comments about how you've really broken polymorphism if you must know the type of object before you can call the speak method. If you absolutely MUST have access to both speak methods, here is one way you could implement it.
public class Animal {
public void speak(String name) {
throw new UnsupportedOperationException("Speak without lives not implemented");
}
public void speak(String name, int lives) {
throw new UnsupportedOperationException("Speak with lives not implemented");
}
}
public class Dog extends Animal {
public void speak(String name) {
System.out.println("My name is " + name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal {
public void speak(String name, int lives) {
System.out.println("My name is " + name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
Alternately you can put the UnsupportedOperationExceptions into the child classes (or you might want to used a checked exception). I'm not actually advocating either of these, but I think this is the closest way to implement what you requested, and I have actually seen systems that used something like this.

Related

Java - How to choose what subclass to construct

I have a parent class:
public class Animal {
public Animal(String name, AnimalTypeEnum type) {
}
}
I have lots (in the case that has caused me to make this over 30) children:
public class Dog extends Animal {
public Dog(String name, AnimalTypeEnum type) {
super(name,type);
}
}
public class Cat extends Animal {
public Cat(String name, AnimalTypeEnum type) {
super(name,type);
}
}
The objects are constructed from many different places in the project (loaded on start up, created at various times in runtime. To "create" an object, I currently use this function (over 30 subclasses in the project, not just 2):
public static Animal create(String name, AnimalTypeEnum type) {
switch(type) {
case DOG:
return new Dog(name, type);
case CAT:
return new Cat(name, type);
}
}
It is important to note that none of the subclasses have any difference in parameters. The reason I'm using subclasses is because they have one or two functions that are overriden.
Say I now wanted to add a parameter for all subclasses, I'd need to:
Add the parameter to the Animal constructor
Add the parameter to the subclass constructors
Add the parameter to the create() function
(also change the parameter wherever the create() function is being called)
Ideally, I'd like to eliminate changing the subclass parameters (none of the subclasses have different parameters) and the create() function from the above process. But if that isn't possible, I'd like to find a better alternative to the create() function. The best solution I've thought of (psuedocode) is:
public Animal(String name, AnimalTypeEnum type) {
if (type == CAT) this.subclass(Cat);
if (type == DOG) this.subclass(Dog);
}
I think the above goes against the principle of class inheritance so I want to be clear that this isn't the solution I am trying to find, just how I imagine a solution could work.
This is a rather trivial issue but I feel that bad programming practices are behind it and I would like to rectify these. My questions would be (incase I haven't properly explained my problem/reasons):
Is inheritance even the ideal way to do this?
Is it possible to eliminate the process of changing the constructor in subclasses in this situation?
Is there anything I can do to remove the create() function, and assign the subclass when constructing Animal?
Thank you.
I think that you wonna use the Factory Pattern, so you have any options for solve your problem #Doleron showed the first one, but you can use this too:
public interface Animal {
public String getName();
}
The implementation Dog
public class Dog implements Animal{
private String name;
public Dog(String name) {
this.name=name;
}
#Override
public String getName() {
return name;
}
}
Cat
public class Cat implements Animal{
private String name;
public Cat(String name) {
this.name=name;
}
#Override
public String getName() {
return name;
}
}
Factory
public class AnimalFactory {
/*
* Some people use static attributs like:
* public static final String DOG ="DOG";
*/
public static Animal creatAnimal(String animal, String name){
if("DOG".equalsIgnoreCase(animal)){
return new Dog(name);
} else if("CAT".equalsIgnoreCase(animal)){
return new Cat(name);
}
return null;
}
}
Main
public static void main(String[] args) {
Animal animal = AnimalFactory.creatAnimal("dog", "pluto");
/*
* if you use static attribut you can call this form
*/
//Animal dog = AnimalFactory.creatAnimal(AnimalFactory.DOG, "pluto");
System.out.println("Name "+animal.getName()+ " class "+animal.getClass().getSimpleName() );
animal = AnimalFactory.creatAnimal("cat", "garfield");
System.out.println("Name "+animal.getName()+ " class "+animal.getClass().getSimpleName() );
}
you can see another example here.
Since you have an enum to identify the instance type, you could avoid the create/switch/if-else approach using a polymorphic enumeration like:
public enum AnimalTypeEnum {
CAT {
public Animal create(String name) {
return new Cat(name);
}
},
DOG {
public Animal create(String name) {
return new Dog(name);
}
},
COW {
public Animal create(String name) {
return new Cow(name);
}
};
abstract Animal create(String name);
}
As everything this approach has pros and cons. Please see if it fits to your requirements.
First of all, the base class Animal should be an abstract class, because you'll never give life to an Animal object but to a more specific type of Animal, i.e Dog, Cat et cetera. In this way, all animals will have some base methods already implemented.However, if some subclass needs to inherit from another class, you should consider Animal as an Interface, because Java doesn't allow multiple inheritance.
For your second question, if I correctly understand, why can't you add a protected member to the base class Animal and initialize it in the Animal costructor? Eventually, if subclasses as a specific value for this parameter, you can set it in the subclasses costructors.
Finally for the create() function in my opinion you should consider the Abstract Factory pattern.

Best way to route method calling from List in Java

What's definitely the best way to call a different method of a class according to a different object type in a List?
common example:
public class Dog extends Animals{
...
public void say(){
System.out("i'm a dog");
}
public class Cat extends Animals{
...
public void say(){
System.out("i'm a cat");
}
public class OtherClass {
public void route(){
List<Animals> aList = new ArrayList<>();
a.add(new Dog());
a.add(new Cat());
for(Animals a:aList)
methodOverloaded(a); ---> that's the point <---
}
public methodOverloaded(Dog d){
d.say();
}
public methodOverloaded(Cat c){
c.say();
}
}
Of course, the metaphorical goal is print I'm a dog on the first iteration and I'm a cat on second running methodOverloaded().
I tried
Visitor Pattern
instanceOf()
but I'm looking for better solution.
edit : I stricrtly want to call the overloaded methods of example's OtherClass.
The best way is to define abstract method in Animal and override it in child classes. That's how the polymorphism works.
No need of overloadings.
public abstract class Animal {
public abstract void say();
}
public class Dog extends Animal {
#Override
public void say() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
#Override
public void say() {
System.out.println("Meow");
}
}
Usage:
public class Main() {
public static void main(String[] args) {
List<Animals> aList = new ArrayList<>();
a.add(new Dog());
a.add(new Cat());
for (Animals a : aList)
a.say();
}
}
Output:
Bark
Meow
____UPDATE_1
I would like to add some comments why the overloading these methods is not a good idea.
If you will add the following to your code - it will compile:
public methodOverloaded(Animal a) {
a.say();
}
But it will not work as you're expecting. It will call public methodOverloaded(Animal a) for all the elements of List.
Why does this happen?
For all iterations of the loop, the compile-time type of the parameter is Animal. The runtime type is different in each iteration, but this does not affect the choice of overloading. Because the compile-time type of the parameter is Animal, the only applicable overloading is the third one.
The behavior of this program is counterintuitive because selection among overloaded methods is static, while selection among overridden methods is dynamic.
The correct version of an overridden method is chosen at runtime, based on the runtime type of the object on which the method is invoked.
This can be fixed with:
public methodOverloaded(Animal a) {
if (a instanceof Cat) ? "Meow" :
(a instanceof Dog) ? "Bark" : "Unknown Animal"
}
Of course suggested option with overriding methods demonstrates better approach and more clean code.
Also, a safe, conservative policy is never to export two overloadings with
the same number of parameters, because it can confuse the client of the API. You can always give methods different names instead of overloading them.
But there is the case when at least one corresponding formal parameter in each pair of overloadings has a “radically different” (when it's clearly impossible to cast an instance of either type to the other) type in the two overloadings.
For example, ArrayList has one constructor that takes an int and a second constructor that takes a Collection. It is hard to imagine any confusion over which of these two constructors will be invoked under any circumstances.
You need to define the method in Animal and make it abstract
abstract class Animal {
public abstract void say();
}
this way, you can override this method in each child of Animal, and all you got to do is a.say()
each object will call their respective method.
You can do it like this:
for(Animals a:aList){
if(a instanceof Dog){
methodOverloaded((Dog) a);
}else if(a instanceof Cat){
methodOverloaded((Cat) a);
}
}
But according to the scenario you have described in the question, #J-Alex answer is a good way to go.
I can show you how "Factory Design pattern" is the suitable way here.
Define you main class like:
public abstract class Animal {
public abstract void say();
}
public class Dog extends Animal {
#Override
public void say() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
#Override
public void say() {
System.out.println("Meow");
}
}
public class FactoryClass{
public static Animal getCorrectAnimal(String type){
if("Cat".equalsIgnoreCase(type)) return new Cat();
else if ("Dog".equalsIgnoreCase(type)) return new Dog();
return null;
}
}
public class TestFactoryClass {
public static void main(String[] args) {
Animal an = ComputerFactory.getCorrectAnimal("Cat");
List<Animals> aList = new ArrayList<>();
a.add(FactoryClass.getCorrectAnimal("Dog"));
a.add(FactoryClass.getCorrectAnimal("Cat"));
for (Animals a : aList)
a.say();
}
}
}
Trust me, if you will analyse the level of Abstraction here, it is awesome. The client/consumer never has to know the Dog or Cat class, he/she just has to know the type and a general abstract class Animal. You can even get rid of type here if you use one higher level of abstraction; you can read "Abstract Factory Design" for that. In this way, you expose the least of your class features (like here you exposed Dog and Cat class by using them directly with new in main class). Please upvote if you are satisfied.

Acceptable use of instanceof [duplicate]

This question already has answers here:
Is this an acceptable use of instanceof?
(2 answers)
Closed 7 years ago.
I'm new to Java and struggling with a design problem. I know use of instanceof may indicate a design flaw and I understand the often given Animal/Dog/Cat classes as example, replacing bark() and meow() with makenoise() etc.
My question is, what is a sensible design if I need to call methods which do not have a corresponding method depending on the type of subclass? For example, what if I want to call a new method biteleash() if the class is a Dog but do nothing at all if it's a Cat?
I did consider having biteleash() in Animal which does nothing, and overriding it in Dog, but there are methods many like this so it seems a clunky solution. In a similar vein, what if the caller needs to do something different depending on which subclass it has hold of, eg. terminate if subclass is a Cat? Is instanceof acceptable here, or is there a better way?
public class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void makeNoise() {
System.out.println("Some noise for a generic animal!");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
public void biteLeash() {
System.out.println("Leash snapped!");
}
}
import java.util.Random;
public class CodeExample {
public static void main(String[] args) {
Animal animal = getSomeAnimal();
System.out.println("My pet is called " + animal.getName());
animal.makeNoise();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.biteLeash();
// do lots of other things because animal is a dog
// eg. sign up for puppy training lessons
}
}
private static Animal getSomeAnimal() {
Animal animal;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(100);
if (randomInt < 50) {
animal = new Dog("Rover");
}
else {
animal = new Cat("Tiddles");
}
return animal;
}
}
Composition will help you here, and is idiomatic in Java.
Design an interface called, say, Leashable. This is implemented by a Dog, but not a Cat.
Rather than using instanceof, you can attempt a reference cast to Leashable to see if it's implemented by your particular object.
In my opinion, you should continue in a similar vein: Build a NoisyAnimal interface too. Perhaps even just Noisy as why should noisiness be pertinent to only animals? Implementing that for a Parrot, say, will have technical challenges beyond a Cat or Dog. Good maintainable programs isolate areas of complexity and composition helps you achieve that.
You shouldn't use concrete classes. Instanceof itself isnt a problem. It exists for a reason. You should use interfaces for loose coupling i.e. your code shouldnt be dependent on concrete class implementations. I suggest you using interfaces wherever possible (i.e. IAnimal instead of Animal)
Instead of checking for Dog, you should use an interface like ILeashable (yeah a bit ridiculous for a name lol), then:
public interface ILeashable {
//add other methods which is connected to being on a leash
void biteLeash();
}
class Dog implements ILeashable {...}
Also there is no one way of doing this, there are certain patterns i.e. decorators or Dependency Inversion which might help you in this case.
Just so you know, this issue you're having is not something you'll generally be facing in the real world. If you have to have implementation-specific logic on some class that implements an interface or an abstract base class, it will usually be because at some higher level you need to get a derived property. This psuedocode to illustrate:
interface ISellable {
decimal getPrice();
}
class CaseItem : ISellable {
int numItemsInCase;
decimal pricePerUnit;
decimal getPrice() {
return numItemsInCase*pricePerUnit;
}
}
class IndividualItem : ISellable{
decimal pricePerUnit;
decimal getPrice() {
return pricePerUnit;
}
}
main() {
aCaseItem = new CaseItem { pricePerUnit = 2, numItemsInCase=5 }; //getPrice() returns 10
anIndividualItem = new IndividualItem { pricePerUnit = 5 }; //getPrice() returns 5
List<ISellable> order = new List<ISellable>();
order.Add(aCaseItem);
order.Add(anIndividualItem);
print getOrderTotal(order);
}
function getOrderTotal(List<ISellable> sellableItems) {
return sellableItems.Sum(i => i.getPrice());
}
Notice that I am using the interface to abstract away the concept of an item's price, but when I'm actually in the main method, I can easily create instances of the specific type in order to control the behaviors of the two classes.
However, when I need to get the price, I'm referencing the items as a list of ISellable, which only exposes their "getPrice()" method for my convenience.
Personally, I always believed the animal methaphor to be severely lacking. It doesn't explain this concept in a way that makes sense, and it doesn't clue you in on how to use it in the real world.
Think of it this way: What event causes the Dog to bite its leash? Or differently speaking, what is your motivation to make it perform this action?
In your example there is actually none. It just so happens that in your main method you decided to put in a check and if the animal you randomly created is a Dog, you make it do certain dog things. That's not how code in the real world works.
When you write code, you want to solve some problem. To stick to the animals example, let's pretend you write a game where you have pets that react to certain events like turning on the vacuum or getting a treat. From this sentence alone we can create a reasonable class hierarchy:
interface Animal {
void reactToVacuum();
void receiveTreat();
}
class Dog implements Animal {
public void biteLeash() {
System.out.println("Leash snapped!");
}
public void wiggleTail() {
System.out.println("Tail is wiggling!");
}
#Override
public void reactToVacuum() {
biteLeash();
}
#Override
public void receiveTreat() {
wiggleTail();
}
}
As you can see, the leash biting happens in response to an event, namely turning on the vacuum.
For a more realistic example, take Android's view hierarchy. A View is the base class for every control on the screen, e.g. a Button, an EditText and so on. View.onDraw() is defined for every view but depending on what View you have, something different will happen. EditText for example will do something like drawCursor() and drawText().
As you can see, the answer to the question "What event causes the EditText to draw the cursor" is "It needs to be drawn on the screen". No instanceof or condition checking necessary.
As in your example - some subclasses can have different methods.
This is typical scenario where you have to use instanceof.
If your subclasses are fixed then you can use animalType to avoid instanceof.
I prefer that u can use interface to check whether the feature is available with the subclass, but it is not feasible for large number of subclass dependent methods. ( solution given by user2710256).
Enum Type {
DOG,CAT ;
}
public abstract class Animal {
String name;
Type type;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void makeNoise() {
System.out.println("Some noise for a generic animal!");
}
abstract Type getType();
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
public Type getType() {
return Type.CAT;
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
public void biteLeash() {
System.out.println("Leash snapped!");
}
public Type getType(){
return Type.DOG;
}
}
import java.util.Random;
public class CodeExample {
public static void main(String[] args) {
Animal animal = getSomeAnimal();
System.out.println("My pet is called " + animal.getName());
animal.makeNoise();
switch(animal.getType())
{
case DOG:
{
Dog dog = (Dog) animal;
dog.biteLeash();
// do lots of other things because animal is a dog
// eg. sign up for puppy training lessons
}
case CAT:
{
// do cat stuff
}
default:
throw new Exception("Invalid Animal");
}
}
private static Animal getSomeAnimal() {
Animal animal;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(100);
if (randomInt < 50) {
animal = new Dog("Rover");
}
else {
animal = new Cat("Tiddles");
}
return animal;
}
}
Of course having biteleash() in a Cat doesn't make sense, for you don't walk cats on a leash. So Animal shouldn't have biteleash(). Maybe you should put a method like playWith() in an Animal, in which Dogs would biteleash(). What I'm trying to say is you probably need to be more general. You shouldn't care if it is a dog to manually call biteleash(). Adding a Ferret to your Zoo would require adding the possibility that the animal is a Ferret, since they can also biteleash().
And maybe a method shouldTerminate(), which returns true in Cats. You will probably want to terminate also on a Tortoise in a while.
Generally, People consider it bad practice, if adding a new subclass would require changes in code using this class.
If I may, this is a highly impractical way to do this, I'm not sure what you are after but instanceof is going to be tedious, what you end up with is high coupling which is a no go when doing OOD.
Here is what I'd do:
First, get rid of class Animal and make it an interface as following
public interface Animal {
public String getName();
public void makeNoise();
public void performAggression();
}
then in dog:
public class Dog implements Animal {
private String name;
public Dog(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
#Override
public void performAggression(){
biteLeash();
}
private void biteLeash() {
System.out.println("Leash snapped!");
}
}
lastly, the cat:
public class Cat implements Animal {
private String name;
public cat(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
#Override
public void performAggression(){
hiss();
}
private void hiss() {
System.out.println("Hisssssss");
}
}
This way you can in you main class just do as following:
public class test{
public test(){
dog = new Dog("King");
cat = new Cat("MissPrincess");
}
public void performAggression(Animal animal){
animal.performAggression();
}
The bonus you get is, you can pass whatever class you want to a method, as long as they implements the same interface, as shown in the test class above in the method performAggression(Animal animal)
All the test class needs to know is those 3 methods, everything else can be done internally in the respective classes without test class needs to know anything about it, hence the "private" visibility on the biteLeash() and hiss() methods.
You end up with a very low coupling and easy to edit later on.
By doing this you effectively also achieve high cohesion because you don't have to get involved in mile long if/ifelse/ifelse...(so on) to determine what kind of class you are dealing with.
Operator instanceof tends to scale well only when applied to interfaces. The reason is that an interface partitions your domain in two: some objects are instances of classes which implement the interface, and the others are not. There is very likely no way that introducing a new class will break your current algorithms that rely on if (x instanceof ISomething) because the new class will either implement ISomething or not. If it does, the if body should cast x to ISomething and make good use of it; if it doesn't then the body of the if is probably of no interest to x.
This is different from the approach in which instanceof is applied to classes. For instance, seals do bark but they are not dogs: you cannot inherit Seal from Dog or viceversa. Hence, as you hinted, you are aware of the fact that if you use instanceof to check whether you can make x bark, you may end up with abominations like this:
if (x instanceof Dog) {
((Dog)x).bark();
}
else if (x instanceof Seal) {
((Seal)x).bark();
}
The solution is to have an interface ICanBark and test for it:
if (x instanceof ICanBark) {
((ICanBark)x).bark();
}
This scales well if you add more animals, whether they can bark or not. But it doesn't scale well if you want to add more noises, because you may be tempted to introduce more interfaces like ICanMeow and the like.
The solution is avoid to be in that situation; ICanBark and ICanMeow are obviously the same behavior IMakeNoise so that there is a single interface implemented by Dog, Cat and Seal.
I'm not a fan of the animal/dog/cat/noise example in the context of polymorphism. Instead I'll show you a real world example of a component system I was working on some time ago. In a component system, components are installed on entities to give them additional behavior. For instance, a monster in a videogame is an entity with some component installed (this stuff is inspired from the Unity 5 engine):
IAudioSource
IRenderer
IMovementAI
ILiving
The four classes that may implement that behaviours may well be something along the lines of:
ScaryGruntingSound
MeshOpenGLRender
StupidQuadrupedAI
Armorless
If you have a collection of entities then it is then totally acceptable (and it is going to scale well) if you instanceof for the interfaces:
for (Entity e : entities) {
for (Component c : e.getComponents()) {
if (c instanceof IAudioSource) {
((IAudioSource)c).play();
}
...
if (c instanceof IUserInput) {
((IUserInput)c).poll();
}
}
}
Since monsters are not controlled by the player, c instanceof IUserInput fails and everybody is happy. The reason why this use of instanceof rocks and the ICanBark/ICanMeow sucks is because IAudioSource/IRenderer/IMovementAI/ILiving are four totally unrelated aspects of what it means to be a monster, while ICanBark/ICanMeow are two manifestations of the same aspect (and should be instead handled by merging them into IMakeNoise).
Edit
I did consider having biteleash() in Animal which does nothing, and overriding it in Dog
It is a clunky solution and I believe it could only be motivated by performance reasons. If I'm not mistaken, Swing for Java uses such a pattern occasionally.

Java: Creating object with String input of the object's name

I have two classes, Dog and Cat:
class Dog{
public void speak(){
System.out.print("Woof!");
}
}
class Cat{
public void speak(){
System.out.print("Meow!");
}
}
In my main, I take the name as String, either "Cat", or "Dog".
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
String name = sc.next();
Class<?> cls = Class.forName(name);
Object object = cls.newInstance();
}
But now I want to be able to call the method "speak". But then I have to cast the object to either cat or dog, since "Object" obviously does not have built in "speak" method. So my solution was to make another class (I can't use if-statements btw):
class Animal{
public void speak(){
}
}
And then both "Cat" and "Dog" can extend Animal and override its methods. Is there any other way to do this WITHOUT making another method / using if-statements? (Including switch case, ternary operator). Thanks in advance.
ANOTHER QUESTION:
If I take in the name of the METHOD in as an input as well, how would I call it? For example:
class Dog{
public void speak(){}
public void bark(){}
}
If I take in as a String either "speak" or "bark", how would I call the method without using if-statements?
You can do it with reflection using Class.getMethod and Method.invoke.
Creating an Animal class is really the cleanest way, though. What stops you from doing that?
You are on the right track. The easiest way is to create an animal class and have dog and cat inherit from it and make them both implement their own version of speak(). Is there a reason you don't want to create another class?
You don't have to create class Animal - create an interface:
interface Animal{
public void speak();
}
and have both Cat and Dog implement it. Then in main():
Class<?> cls = Class.forName(name);
Animal animal = cls.newInstance();
animal.speak();
No need to cast or use if/else.
The only reason to use inheritance/abstract classes is when you want to reuse functionality (implement a method once and use it in a few classes). Otherwise - better use interfaces.
As for the method name, if you want the "wise-ass" solution: use switch (supported from Java 7). Otherwise, see #immibis's answer.
Alright, here are two methods ordered by preference:
abstract class Animal {
public abstract void speak();
}
class Dog extends Animal {
#Override
public void speak() {
System.out.println("Woof woof");
}
}
class Cat extends Animal {
#Override
public void speak() {
System.out.println("Miauw");
}
}
public static void main(String[] args) {
String type = "Dog";
Class<?> clazz;
try {
clazz = Class.forName(type);
Animal pet = (Animal) clazz.newInstance();
pet.speak();
} catch (Exception e) {
e.printStackTrace();
}
}
I'm using a baseclass since it can be assumed that an Animal will hold more fields that are shared by each animal (name, species, etc). If this isn't the case then you should go for an interface.
Or with reflection:
public class Test {
public static void main(String[] args) {
String type = "Dog";
Class<?> clazz;
try {
clazz = Class.forName(type);
for(Method method : clazz.getMethods()){
if(method.getName().equals("speak")){
method.invoke(clazz.newInstance(), null);
}
}
} catch (CException e) {
e.printStackTrace();
}
}
}

Is this still polymorphism?

While coding, I got an interesting doubt about polymorphism and I couldn't understand a solution for this.
public class Animal {
public void getLegs() {
SOP("4 legs");
}
}
public class Kangaroo extends Animal {
public void getLegs() {
SOP("2 legs");
}
public static void main(String[] args) {
Animal a = new Kangaroo(); // without changing this how can I get Animal getLegs
SOP(a.getLegs()); // Important Line
}
}
Now If I want to call the getLegs method of Animal, how do I? Is it possible? Is it still polymorphism?
Yes, it is the most basic form of demonstrating polymorphisim.
Basically you are dealing with an Animal named a. When you call a.getLegs() your code doesn't bind to the implementation of getLegs() in Animal, rather it binds to the lowest sub-class implementation, getLegs() in Kangraoo().
If the Animal has an implementation, it is said to be hidden by the subclass implementation. If Animal has no implementation, then it is not possible to construct stand-alone classes of Animal as they lack implementations for all of the required methods, and under such a circumstance, Animal is said to be an abstract class (one that cannot be constructed directly, but only can be constructed by it's sub classes).
If you really want to call your method for Animal, and you can employ a static method, you can use hiding instead of overriding.
It works as follows: for static methods only, the called method is the one related to the declared type, not the object instance. In other words, it follows the class because the method is a class method, not an instance method.
An example, adapted from this page:
public class Animal {
public static void testClassMethod() {
System.out.println("The class" + " method in Animal.");
}
public void testInstanceMethod() {
System.out.println("The instance " + " method in Animal.");
}
}
public class Kangaroo extends Animal {
public static void testClassMethod() {
System.out.println("The class method" + " in Kangaroo.");
}
public void testInstanceMethod() {
System.out.println("The instance method" + " in Kangaroo.");
}
public static void main(String[] args) {
Kangaroo myRoo = new Kangaroo();
Animal myAnimal = myRoo;
myRoo.testInstanceMethod();
myAnimal.testInstanceMethod();
Kangaroo.testClassMethod();
Animal.testClassMethod();
}
}
The result will be (pay attention to the 3rd and 4th lines, as opposed to the 1st and 2nd):
The instance method in Kangaroo.
The instance method in Kangaroo.
The class method in Kangaroo.
The class method in Animal.
In Java it's not possible to access Animal's implementation. It will always return Kangaroo's version.
(Note in C# it is possible by tagging the overriding method with "new", but it's a fairly specialised use case).
Accessing what appears to be an Animal but getting the behaviour specified by Kangaroo is exactly what polymorphism is - the ability for a child object to be substituted wherever its parent is expected.
In general you wouldn't want to have the calling code know about the inheritance hierarchy because this would tightly couple your code together. If you genuinely need to access Animal's implementation of this method it suggests your design is probably wrong.
The spirit of Polymorphism is to execute different code decided at runtime. To make it more clear, I'll modify your code a bit.
public class Animal {
public void getLegs(){
SOP('4 legs');
}
}
public class Kangaroo extends Animal{
public void getLegs(){
SOP('2 legs');
}
public static void main(String[] args){
Animal a = new Kangaroo(); //without changing this how can I get Animal getLegs
Kangaroo kng= new Kangaroo ();
Animal an = new Animal();
SOP(a.getLegs()); // Kangaroo's version is called
SOP(kng.getLegs()); //Again, Kangaroo's version is called
SOP(an.getLegs()); //Animal version is called
}
}
and Yes, as all say you can't call Animal from your line Animal a = new Kangaroo();..as none will want to do it. Rather he will directly write. Animal a = new Animal();..
So finally it is the object not referance which decides which method will be called
Now If I want to call the getLegs method of Animal, how do I? Is it possible?
If you want to access the overridden method - which contradicts polymorphism - you can use reflection. Get the getLegs method from Animal's class, and then invoke it on your Kangaroo object. However, this is a hack, and not something you'd do in a regular program.
SOP( Animal.class.getMethod("getLegs").invoke(a) );

Categories

Resources