For example i have class Animal, and class Cat (Bird, Dog, Fish ...) which extends Animal. Now I want to declare class Pet, which is also Animal, and I want it to be built from any existing Animal, e.g. Cat.
So I need constructor like this:
class Pet extends Animal{
private String nickname;
private Animal kind;
Pet(Animal a, String nickname){
<...>;
this.nickname = nickname;
}
}
EDIT:
I want something like this:
Cat cat = new Cat();
Animal pet = new Pet(cat, "Foo");
if (pet instanceof Pet){
if (pet.kind instanceof Cat){
Pet.sayMeow();
}
}
Is that means that I just need Animal()(which is protected) constructor in <...> ?
Even after your edit, your intentions aren't really clear to me. It seems as if you're simply looking to find a way that allows you, at runtime, to say: "This cat was a stray before but it just became someone's pet now!".
If that's right, you could go for a very simple and straight forward solution -
add this feature right to the Animal class:
public class Animal {
private boolean isPet = false;
private String nickname = "";
public Animal() {
/*...*/
}
public makeStray() {
isPet = false;
nickname = "";
}
public makePet(String nickname) {
isPet = true;
this.nickname = nickname;
}
public boolean isPet() {
return isPet;
}
public void makeNoise() {
/* Override in child classes */
}
}
According to your example, you could then simply do:
Animal cat = new Cat();
cat.makePet("Foo");
if (cat.isPet()) { // Apparently, only pet cats ever meow.
cat.makeNoise(); // Cats will meow, dogs will bark, ...
}
Note, however, that this way of coding can quickly bloat up a class. It really depends on what you're planning to do with it other than this. I'd say this is the quick 'n' dirty solution.
For more sophisticated solutions, check the other answer(s).
EDIT1: As Fildor correctly pointed out, having a method sayMeow() isn't such a good idea. Better have a makeNoise() method in Animal and override it in the child classes to get the specific behavior for the different kind of Animals. Now, if you never want to actually create an instance of the Animal class, you could also make the class abstract, as well as the makeNoise() method. This would ensure that every child class has to implement the makeNoise() method. Or maybe you are fine with the default behavior of mute animals if the method isn't overridden.
EDIT2: This answer to a related questions might shed more light on your situation. It is about C#, but the principles translate to Java.
What you describe is perfectly possible and commonly known as "Decorator Pattern".
Link-Only answers are bad, I will elaborate later when I have more time.
Meanwhile, Wikipedia has more Info: Decorator Pattern.
1 Cat cat = new Cat();
2 Animal pet = new Pet(cat, "Foo");
3 if (pet instanceof Pet){
4 if (pet.kind instanceof Cat){
5 Pet.sayMeow();
6 }
7 }
This has the disadvantage that you need to use instanceOf. Usually, you would have your Animal class have a method - let's call it makeNoise. Probably abstract. You Animal-Implementations ( Cat, Dog... ) then would override that method to make their respective noise ("Bark","Miow" ...).
In the snippet, it seems only Pets can make noises ... that makes it a little bit more complicated because there would be various ways to do that.
You could have the decorator save a sound and override the makeNoise to make that sound. Like so:
Cat catInstance = new Cat();
catInstance.makeNoise(); // Default impl: NOP => "" - no sound.
Animal pet = new Pet( catInstance, "Mieow" );
pet.makeNoise(); // => "Mieow"
The point of all this is: You want to avoid using instanceof. You don't care if the Animal is a Cat a Dog, a Pet-Cat or a Pet-Dog. They shall make their correct sounds if and when told to. So you could have a Collection of "Animal"s and tell them all to "makeNoise" and each will remain silent, bark or mieow without you having to care for if they are pets or which specific child of Animal.
EDIT: Reading my answer again, it is more like a Policy (Strategy pattern) than a Decorator.
The Policy changes how something is done, while the Decorator would add the feature.
So to be a true Decorator, it would mean that makeNoise would be in the interface of Pet. Which means you couldn't call that method on Animals.
That is why I change my suggestion from "Decorator" to "Strategy" pattern.
The example above still holds. You would kind of have a "default" Strategy and inject the "Pet"-Strategy by using a Decorator-Like implementation approach.
Of course all of this could also be done differently to implement the pattern more strictly.
At last, if( x instanceof X) ... always jingles the "Visitor"-Bell, too.
Related
This question already has answers here:
What is the main difference between Inheritance and Polymorphism?
(18 answers)
Closed 6 years ago.
Imagine that we have a class Animal that extends to three other classes: Dog, Cat, Bird.
This animal class has a talk() and move() function. The talk function outputs "Animal talking" and the move function outputs "Animal moving".
For a dog, this is "Dog moving" and "Dog eating". For the Cat and Bird class, this difference is paralleled "Cat moving" etc.
Now, because of polymorphism, if I do
Animal charlietheBird = new Bird()
and then call in
charlietheBird.talk()
it will output
Bird talking
because the output is determined at runtime since the compiler knows that charlie is a type of Animal of the class Bird.
HOWEVER!!
I can simply do
Bird charlietheBird = new Bird();
and then calling charlietheBird.poop(); will give the same output, because the
method would have been overridden.
What can polymorphism do that inheritance can't?
The real advantages of Polymorphism can be seen at runtime rather than compile time. Polymorphism allows you to substitute one implementation for another without the need to change the code that uses it. Let's take your example of the Animal hierarchy. Let's say you have a Vet that knows how to perform health checkups on any animal (Yup he's a supervet).
class Vet {
private Animal animal;
public Vet(Animal animal) {
this.animal = animal;
}
public void perfromCheckup() {
animal.talk();
animal.poop();
}
}
You can now say :
Vet vetWithBird = new Vet(new Bird());
Vet vetWithDog = new Vet(new Dog());
vetWithBird.performCheckup();
vetWithDog.performCheckup();
Notice how you can tell the Vet to perform a checkup on a Bird or a Dog or any other animal for that matter without needing to change your Vet class. At runtime, the Dog would bark when it goes for a checkup and the Bird would tweet when it goes for a checkup. Imagine if instead of Animal, the Vet had a Bird reference :
class Vet {
private Bird bird;
public Vet(Bird bird) {
this.bird = bird;
}
public void perfromCheckup() {
bird.talk();
bird.poop();
}
}
The poor Vet is now only going to be able to work with a Bird. Tell your Vet to work with a Dog and he will reject this right away.
Vet vetWithBird = new Vet(new Bird()); //Works fine. Vet likes birds.
Vet vet = new Vet(new Dog())// compilation error. Sorry I don't like dogs.
In summary, Polymorphism allows you to substitute subclass instances where a super-class reference is used. Inheritance allows you to inherit code from a parent class and possibly redefine that behavior in subclasses so that your code can take advantage of it at runtime through Polymorphism
Inheritance supports Polymorphism but Polymorphism does not depend on Inheritance.
You gave an example how to achief Polymorphism via Inheritance.
But you could look at it differently:
There is an interface for the concept of moving:
interface Movable{
void move();
}
Animals may implement this interface:
class Dog implements Movable {
#Override
public void move(){
// move the animal
}
}
but some fungis can also move:
class SlimeMold implements Movable {
#Override
public void move(){
// move the animal
}
}
There is hardly to find an "is a" relationship between those two which could be expressed by inheritance, but when both implement the same interface we can still apply Polymorphism on them:
Collection<Movable> movables = new HashSet<>();
movables.add(new Dog());
movables.add(new SlimeMold());
for(Movable movable : movables)
movable.move();
Inheritance refers to a feature of Java programming that lets you create classes that are derived from other classes. A class that's based on another class inherits the other class. The class that is inherited is the parent class, the base class, or the superclass.
Polymorphism refers to a programming language's ability to process objects differently depending on their data type or class. More specifically, it is the ability to redefine methods for derived classes.
You can find more information in Objects and Java by Bill Venners Chapter 7:
Polymorphism and Interfaces
I have the following classes :
public abstract class Animal
{
private String species;
public Animal(String ll)
{
species = ll;
}
public abstract void speak();
public String toString()
{
return "Species: " + species;
}
}
The 2nd class:
public class Raven extends Animal
{
String name;
public Raven(String emri)
{
super("Raven");
name = emri;
}
public void speak()
{
System.out.println("krra krra");
}
public String toString()
{
return super.toString() + "\nName : "+ name ;
}
}
and the test class :
public class TestAnimals
{
public static void main(String args[])
{
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
System.out.println(a.toString());
}
}
When I execute the test class, I get :
Species: Raven
Name: Ziosh
What I don't understand is why does Java use the "new" toString() method, even after we "upcast" the Raven object to Animal ?
Thanks.
Because that's what polymorphism is all about: you can call a method of an object without knowing the actual concrete type of the object, and the appropriate method, defined in this concrete type, will be called.
This works exactly like real objects: if I give you a car, even if you don't know it's actually a hybrid car, the car will behave like a hybrid car when you drive it.
In your example, a and blabla are two references to the same object, which is a Raven instance. So this object *speak*s and *toString*s like a Raven.
When you call a method in java, even if it's cast to the super type, it always looks for the most overridden method to call.
From http://docs.oracle.com/javase/tutorial/java/IandI/override.html
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
Here, a and blabla reference the exact same object, as you can confirm with:
System.out.println(a == blabla);
// prints "true"
As such, a is really a Raven, so naturally it will talk like a Raven, even if you label it an Animal.
Consider another explanation in human terms. Letting the implementation to be executed on an object of a subclass could be actually very dangerous. Imagine a Bicycle class, and its more specialized BicycleWithLittleWheels. The thing about the latter, the little wheels are quite fragile, and if you try to ride it too fast, they could break. If you let somebody ride that bicycle as if was a regular bicycle, completely obvious of the little wheels, he may break it. By similar logic, you probably shouldn't use a high-precision dental drill the same way as a sledgehammer.
This is why, intuitively, you shouldn't let a specialized object be treated as its more general form. Sure, in some cases, it may make sense to use a specialized object as if it was something more general, but not always. How could the compiler distinguish the safe cases from the unsafe cases? That would be too difficult. So to stay on the safe side, the language won't let you do this.
Java always uses the method of the instance as describe in this post:
java override method invocation
Imagine I have this:
public class Animal {
private String racaAnimal;
private String corAnimal;
public String getCorAnimal() {
return this.corAnimal;
}
public String getRacaAnimal() {
return this.racaAnimal;
}
public Animal getAnimaisCliente(int indice) {
return this.animaisCliente[indice];
}
}
public class Estimacao extends Animal{
private String nomeAnimal;
public String getNomeAnimal() {
return nomeAnimal;
}
}
public class Cliente{
private Animal[] animaisCliente;
}
Constructors aren't showing but they are working fine.
I have one arraylist that holds all Cliente
ArrayList<Cliente> clientes = new ArrayList<Cliente>();
And a animal is created like this
Estimacao animaisEstimacao = new Estimacao(nomeAnimal,racaAnimal,corAnimal);
and then its added to the array of Animal in Cliente
Now if I do this:
System.out.println(" Raça: " + clientes.get(0).getAnimaisCliente(0).getRacaAnimal());
It works.
But how can i get nomeAnimal from class Estimacao?
If i put
System.out.println(" Nome: " + clientes.get(0).getAnimaisCliente(0).getNomeAnimal());
it do not works.
From a subclass we can get things from the super class but the other way arroud? is it possible?
You need to cast your Animal to Estimacao. But obviously, if you don't want to risk an exception, make sure your Animal is of the right class before:
Animal animal = clientes.get(0).getAnimaisCliente(0);
if (animal instanceof Estimacao) {
System.out.println(" Nome: " + ((Estimacao) animal).getNomeAnimal());
}
Think of it this way: an instance of a subclass is also an instance of the superclass. But an instance of the superclass is not necessarily an instance of the subclass. Thus the superclass methods are always available in both, but the subclass methods are only available in the subclass.
If you are sure you have an instance of the subclass, you can cast it explicitly and call the subclass-specific method on it, but you need to take care in doing so.
Try
System.out.println(" Nome: " + ((Estimacao) clientes.get(0).getAnimaisCliente(0)).getNomeAnimal());
In addition to the answers provided above, you may want to just consider the general design of your classes. If the nomeAnimal is something that the Animal class should really be aware of then it might make sense to push it up (even the name of the variable suggests its Animal-ness).
If not, then you may want to further consider leveraging polymorphism by adding a displaySpecificInfo() to the Animal class and either making it abstract, or adding an empty implementation in the Animal class. That would allow you to call it from where your current - failing - print call is, and then have the current line in the derived class's implementation. This would save the need for the cast (not that there's anything wrong with casting), as well as create a more OO/Encapsulation-compliant implementation.
Edit:
Excellent note by #Guillaume and my apologies for potentially peeling back more layers of the OO onion then you are interested in! :)
Cast the Animal to a Estimacao to access the methods defined in Estimacao
It is not possible directly as you are asking. However, you could add getNomeAnimal() in your base class (Animal), that would return null or an empty string - then the instances which are of Estimacao class will return the correct values.
This is a misplaces usage in your animal class:
this.animaisCliente[indice] // animaisCliente is not an attribute of Animal
No you can't do it unless you cast the Animal type object to Estimacao type. Only after the cast, the getNomeAnimal() will be available to you. But this is a bad thing to do. If your array contains a mix of Animal type and Estimacao type objects then it will fail with ClassCastException.
I give lessons on the fundamentals of the Java programming language, to students who study this subject in college.
Today one of them got me really confused with her question, so I told her to give me just a day to think about the problem, and I'll give her as accurate of an answer as I can.
She told me that the teacher got really angry when she used the keyword instanceof in her exam.
Also, she said that the teacher said that there is not a way to prove how polymorphism worked if she used that word.
I thought a lot to try to find a way to prove that in some occasions we need to use instanceof, and also that even if we use it, there still some polymorphism in that approach.
So this is the example I made:
public interface Animal
{
public void talk();
}
class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
public class Cat implements Animal
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
My conclusions are the following:
The first approach (APPROACH 1) is a simple demo of how to program to an interface, not a realization. I think that the polymorphism is clearly visible, in the parameters of the method makeItTalk(Animal animal), and also in the way the method talk is called, by using the animal object.(This part is ok)
The second part is the one that makes me confused. She used instanceof at some point in her exam (I don't know how their exam looked like), and that was not accepted correctly because the teacher said, you are not proving polymorphism.
To help her understand when she can use instanceof, I thought about telling her, that she can use it, when the method she needs to call is not in the interface, but it is just in one of the implementing classes.
As you can see, only cats can climb to trees, and it would not be logical to make a Hippopotamus or a Dog climb to a tree. I think that could be an example of when to use instanceof
But what about polymorphism in approach 2?
How many uses of polymorphism do you see there (only approach 2)?
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
What do you think, is it correct?
If yes, how would you explain with your own words, that casting relies on polymorphism?
The reason the instanceof method is seen as bad is simple. Cats aren't the only Animal that might be able to climb a tree.
What happens if down the road you need to add a Koala class. Then your simple if becomes a not so simple or. Then, what happens when you add another class? and another one. And another one. That's the prime reason why instanceof is seen as bad. Because it couples the implementation to a concrete class, rather than opening it for the callee to determine what to do.
Simply implement the makeItClimbToATree() method to throw a CantClimbTreesException if called on an animal that can't climb. That way you have the best of both worlds. Easy to implement, and easy to extend.
IMHO, instanceof has only 1 truly valid use: In a test case to test the returned instance from a method matches the expected return type (in non-type safe languages).
Basically any other use can more than likely be refactored away or designed differently to negate the need for its use.
Another way to look at it is this: Polymorphism allows you to eliminate almost all conditional statements from your code. The only conditionals that you can't get rid of (at least all of them) are in object creational methods (such as in a factory where it must choose the class based upon a runtime argument). Just about any other conditional can be replaced by polymorphism. Therefore, anything that does conditional execution is by definition anti-polymorphic. That's not to say it's bad (there's a huge difference between Good and Good Enough), But in an academic discussion, it's not polymorphic...
Never forget the 60/60 rule. 60% of your total development time will be spent maintaining the code you wrote, and 60% of that time will be spent adding new features. Make maintaining easier, and your life will be easier as well. That's why instanceof is bad. It makes the initial design easier, but complicates the long term maintenance (which is more expensive anyway)...
In your above example, there is no need to call
makeItClimbToATree (new Hippopotamus ());
It could be easily avoided, if makeItClimbToATree wouldn't expect an animal, but something more specific, which is really able to climb a tree. The necessity to allow animals, and therefore to use instanceof, isn't visible. If you manage the animals in a List of animals, it will be more obvious.
While ircmaxells explanation starts great, while introducing the Koala and other TreeClimbers, he doesn't see a second extension which is hiding in a sea anemone: different capabilities of animals like seaAnemoneHider, winterSleeping, blueEyed, bugEating, and so on, and so on. You would end up with boolean over boolean, constantly recompiling the base class, as well as breaking extending customer classes, which would need recompilation again, and wouldn't be able to introduce their own possibilities in a similar manner.
Customer A would need Customer B to declare a NotBugEatingException, to get your behaviour into the base class.
Introducing your own interfaces, combined with instanceof, is a much cleaner approach, and more flexible. Customer A might define divingLikeAPenguin and customer B trumpeting, both not knowing of each other, both not affecting the Animal class and not provoking useless recompilations.
import java.util.*;
interface Animal {
public void talk ();
}
interface TreeClimbing {
public void climbToATree ();
}
class Dog implements Animal {
public void talk () { System.out.println("Woof!"); }
}
class Cat implements Animal, TreeClimbing {
public void talk () { System.out.println("Meow!"); }
public void climbToATree () { System.out.println ("on top!"); }
}
public class TreeCriterion {
public static void main(String[] args) {
List <Animal> animals = new ArrayList <Animal> ();
animals.add (new Cat ());
animals.add (new Dog ());
discuss (animals);
upTheTree (animals);
}
public static void discuss (List <Animal> animals) {
for (Animal a : animals)
a.talk ();
}
public static void upTheTree (List <Animal> animals) {
for (Animal a : animals) {
if (a instanceof TreeClimbing)
((TreeClimbing) a).climbToATree ();
}
}
}
We don't need a third animal, dog and cat are enough. I made them default visible instead of public, to make the whole example fit into a single file.
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
No. Especially, since Cat is a leaf class in the example.
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
Polymorphism requires the IS-A relationship, but not the other way round.
Polymorphism is when you dispatch to (potentially) different methods based on an abstract interface. If you don't have that dispatching, then it is not using polymorphism. In your example, using instanceof to cast to a class with no subclasses, you are removing the need for dispatching.
(Of course, there is more than one way to "do polymorphism" in Java. You can implement it using interfaces, using abstract classes, or using concrete classes with subclasses ... or hypothetical subclasses that may be written in the future. Interfaces (and dispatching based on an interface) are generally the best way because they give a clean separation of the API from the identity of class.)
And on a separate note, using instanceof like that is typically a sign of poor design and / or poor modelling. Specifically, it hard-wires the assumption that only cats can climb, which is trivially falsified if we include other animals into the model / program. If that happens, your code breaks.
Maybe I'm missing the point and don't get the context of the exam question, but whether an Animal can climb a tree should be a part of the class that implements Animal. For example, if Animal is an interface, you could have a method boolean isCapableOfClimbing() and then each implementing class would be able to indicate its capability.
A method that attempted to make the animal climb could then use that. It doesn't make sense for a method that's trying to make the animal climb a tree check whether it's an instance of a particular class, since then that method is specifying something that should be specified in the implementing class. A simple method should not provide behaviour for a class that it's using.
As for your question of when to use instanceof, once place where it will almost always be used is if overriding the equals() method of a class, since it only accepts an Object and you typically have to ensure it is of the same type so it can be cast and then meaningfully compared.
What about something like the code below? It solves the generality problem by separating the tree-climbing as another interface you can implement or not on your animals. It fits the problem better: climbing trees is not an intrinsic property of all animals, only of a subset of them. At least to me it looks much clearer and elegant than throwing NotImplementedExceptions.
public interface Animal {
public void talk();
}
public interface AnimalCanClimbTrees extends Animal {
public void climbToATree();
}
public class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
/* Animal is probably not needed, but being explicit is never bad */
public class Cat implements Animal, AnimalCanClimbTrees
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof AnimalCanClimbTrees) {
((AnimalCanClimbTrees)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
The instanceof operator has nothing to do with polymorphism. It is simply used to see whether or not an object is an instance of a particular class. You see this operator being used a lot in the equals() method, because the method takes a generic Object as a parameter:
public class Cat implements Animal{
#Override
public boolean equals(Object obj){
if (obj == null || !obj instanceof Cat){
//obj is null or not a "Cat", so can't be equal
return false;
}
if (this == obj){
//it's the same instance so it must be equal
return true;
}
Cat catObj = (Cat)obj; //cast to "Cat"
return this.getName().equals(catObj.getName()); //compare the two objects
}
}
If a class does not implement a method, then it should throw an exception. I believe the "official" exception you are supposed to throw is UnsupportedOperationException. To be "correct", I think the Animal interface should have a public void climbToATree(); method. The climbToATree() methods in the Dog and Hippo classes should throw an UnsupportedOperationException because they cannot implement this method. But if you are throwing this exception very often, then there may be something wrong with your object model, as this is not a common thing to do I don't think.
Also note that it's helpful (but not required) to use the #Override annotation with polymorphic programming in Java. This will cause a compilation error to be thrown if a method with this annotation does not override a parent method, implement an abstract method, or (in Java 6) implement an interface method. This can help catch any mistakes you make in the method signature. For example:
public String tostring(){
return "foobar";
}
Without the annotation, the program would compile and run successfully. But this was not your intention! You wanted to override toString(), but you accidentally spelled the name wrong!!
I'm surprised no one wrote anything about Late Binding. Polymorphism in Java = Late Binding. The method being called will be be attached to the object when we finally know its type. In your example:
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
You are calling climbToATree() on a Cat object so the compiler accepts it. At run time, there is no need to check the type of the calling object since climbToATree() belongs to Cat only. And so there is no polymorphism in these lines of code.
About casting being related to Polymorphism, it isn't. Casting just limits the fields that are shared in both objects, if the cast is legal. You could do this:
class A {
int getInt() {}
}
class B extends A {
int getInt() {}
}
// in main
A a = new B();
A b = (A)a;
b.getInt(); // This would still call class B's getInt();
The cast itself added no value, getInt() was bound at run time to the runtime type of a, which was class B.
A polymorphic and OOP approach would be to place the method makeItClimbToATree on the Animal interface:
public interface Animal{
public void talk();
public void makeItClimbToATree();
}
Then the implementors of Animal would provide the behavior for the method, which for all other than Cat could be to throw an exception. This is polymorphic because you operate on different implementations of Animal through a single method.
The function which uses the instanceOf operator is considered "bad" OOP because it requires knowledge of all the implementation types to determine the behavior of the method.
I am trying to understand Java's polymorphism, and I have one question about downcasting an object.
Let's say for this example I have two subclasses Dog and Cat that inherit from a superclass Animal
From what I understood, the only way to downcast an object is if this Object is already of the good type, like this:
Animal a = new Dog();
Dog d = (Dog) a;
This works right?
But what if I want to create a regular animal without knowing what it would be, and then cast it when I know, how can I do that?
Animal a = new Animal();
Dog d = (Dog) a;
This will throw a ClassCastException at runtime right?
The only way I found to do that is to create a new Dog constructor that creates a dog from a regular animal:
Animal a = new Animal();
Dog d = new Dog(a);
with
public Class Dog extends Animal{
public Dog(Animal a){
super(a);
}
}
So my question is, how am I supposed to do this?
Am I doing it the best way?
Am I not supposed to do this at all, if I have to it means my program is not well conceived?
Is there a better way I missed?
Thanks a lot!
nbarraille
If you want to create an instance of a type that may vary depending upon non-local conditions, use an Abstract Factory (as described in the Design Patterns book).
In it's simplest form:
interface AnimalFactory {
Animal createAnimal();
}
class DogFactory implements AnimalFactory {
public Dog createAnimal() {
return new Dog();
}
}
Note also there is a difference between the static type of a reference and the dynamic type of the object. Even though you have an Animal reference, if the original object is a Dog, it still behaves like a Dog.
You should only cast to a class that the object really is, so if you have a Dog that extends Animal you can cast it to an Animal (because it is one) but you shouldn't cast an Animal to a Dog because not all Animals are Dogs. The Dog class may well have extra fields that are not implemented by the Animal class and so the cast doesn't make sense (what do you initialise those values to?).
Java is a strongly typed language, and that means you can only cast an object to a type it extends from (either a superclass or an interface).
Even if you "fake it", e.g. copy all a classes methods and fields, you just can't cast an object to a type it doesn't extend.
public class Foo{
public String phleem;
public void bar(){
}
}
public class Bar{
public String phleem;
}
public interface Baz{
public void bar();
}
Given the above code, you can't cast a Foo object to either a Bar or a Baz, although the class structure seems to imply that you could. There is no inheritance involved, so a ClassCastException is thrown.
Here you are talking about downcasting, so in this scenario always superclass should be used as a reference and child object should be pointed by that.
This usd basically in factory patter.