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.
Related
I'm trying to figure out whether implementing individual methods of a subclass in an abstract superclass, or casting is the better way to go about the following scenario.
Suppose I have an abstract class Animal which has two subclasses, Dog and Cat and a Main class where I save objects of Dog and Cat in an Animal array. The following is how I would go about using methods of the subclasses in a more generalized array.
class Main{
public static void main(String[] args){
Animal[] animalArray = new Animal[2];
animalArray[0] = new Cat();
animalArray[1] = new Dog();
for (Animal a : animalArray){
if (a.getClass().equals(Dog.class){
((Dog)a).bark();
} else {
((Cat)a).meow();
}
}
}
}
However a friend suggested that casting isn't best practice, and that I should define each method in the abstract superclass in the following way:
public abstract class Animal{
public abstract String meow(){
return null;
}
public abstract String bark();
return null;
}
}
After setting the return values of these methods to null I would need to use #Override and implement them in the respective subclasses.
Which way is better? I'm afraid the abstract class will be too large and will have methods assigned to subclasses that don't make sense (even if all they do is return null). I think by using casting I can make more precise uses of the methods.
meow() and bark() shouldn't be defined in the Animal class. These methods are specific to Cat and Dog classes.
You should define an abstract method as shown below, in the Animal class and override it in the sub classes.
public abstract class Animal {
public abstract String action() {};
}
public class Dog extends Animal {
#Override
public String action() {
//your implementation (bark)
}
}
public class Cat extends Animal {
#Override
public String action() {
//your implementation (meow)
}
}
Hope it answers your query.
I am at a lookout for a design pattern for my simple problem. Here is a simplified version.
class Animal{...}
class Dog extends Animal{...}
class Cat extends Animal{...}
... // so on, 3 other classes as of now
I have a static method (in reality exposed via web-service but its synonymous) which takes an id and returns an animal.
If a cat is returned then the other team using the cat object generates a CatReport. If Dog, then dog report (They can use it for anything). Obviously Cat & Dog have different attributes. Cat and Dog don't have anything else in common apart from the fact that they are Animals. So making a call like below, is insufficient because I need the precise type:
public static Animal getAnimal(int id){}
Not sufficient because animal does not contain all the information what the precise type can give me.
What is the best way to deal with this problem?
PS: In Scala, I would simply do pattern-matching on the object. This solves the problem elegantly.
One solution I have is: make a call which returns an enum signifying what the id corresponds to. And then have a separate call for each:
public static AnimalType getAnimalType(int id){}
public static Cat getCat(int id){}
public static Dog getDog(int id){}
....
But this is cumbersome.
In a language like Java, you can simulate pattern matching behavior using the Visitor pattern.
You can do it in some steps :
Define an interface Animal representing an Animal with a accept method
Add some subclasses to Animal and give the same implementation like in my little example below.
Define an interface Visitor and give it an implementation. This classe will allows to you to simulate some pattern matching on your classes.
Here a little example :
public interface Animal {
public void accept(AnimalVisitor v);
}
public class Dog extends Animal {
public void accept(AnimalVisitor v) {
v.visit(this);
}
}
public class Cat extends Animal {
public void accdept(AnimalVistior v) {
v.visit(this);
}
}
public interface AnimalVisitor {
public void visit(Dog d);
public void visit(Cat c);
}
public class PrintAnimal implements AnimalVisitor {
public void visit(Dog d) {
System.out.println("Dog");
}
public void visit(Cat c) {
System.out.println("Cat");
}
}
Visitor pattern is a elegant way to solve your problem and also it's avoid the accumulation of if (x instance of bar) in one function. With this pattern, your code will be more readable and easier to extend.
The corresponding Scala code to make an idea of my answer:
abstract class Animal {}
case class Dog() extends Animal
case class Cat() extends Animal
object Animal {
def printAnimal(a : Animal) = a match {
case x : Dog => "Dog"
case x : Cat => "Cat"
case _ => "Unknown"
}
def main(args : Array[String]) = {
println(printAnimal(Dog()))
}
}
Well, I don't see any really elegant solution but you can create a kind of report factory with this kind of code
public Report getCorrespondingReport(Animal animal){
if(animal instanceof Dog) return new DogReport();
if(animal instanceof Cat) return new CatReport();
...
...or you could make a generic report and use reflection to inspect your Animal instance and generate your report following general rules but it might not be doable.
If I understand the question correctly, you want to call correct implementation of methods regards of the type of object you have. So if an animal is a cat, generate report method should be called from Cat class if you have code like below
public static Animal getAnimal(int id){
//your code to return object of either Cat or Dog
}
animal.generateReport();
First of all as you said,
Obviously Cat & Dog have different attributes. Cat and Dog dont have
anything else in common apart from the fact that they are Animals.
As the subclasses do not have any common functionality, define Animal as an interface instead of a class like given below
interface Animal{
public void generateReport();
}
And create Cat and Dog like this
class Cat implements Animal{
//define cat specific attributes here
public void generateReport(){
//your logic to generate cat report
}
}
class Dog implements Animal{
//define dog specific attributes here
public void generateReport(){
//your logic to generate dog report
}
}
Since the generateReport() method is defined in interface, all the classes implementing the interface must have generateReport().
So when you make a call like this,
public static Animal getAnimal(int id){
//your code to return object of either Cat or Dog
}
animal.generateReport();
the underlying object's method will be called.
If you simply want to know what animal object refers to (returned from getAnimal method i.e. either Cat or Dog), you can check it like below
class Animal{
}
class Dog extends Animal{
public String dogName = "Dog1";
}
class Cat extends Animal{
public String catName = "Cat1";
}
public class HelloWorld{
public static void main(String []args){
//call getAnimal and get the object instead of following line
Animal animal = new Cat();
if ( animal instanceof Cat ){
//cast Animal to Cat
Cat cat = (Cat) animal;
System.out.println(cat.catName);
}else if ( animal instanceof Dog ){
//cast Animal to Dog
Dog dog = (Dog) animal;
System.out.println(dog.dogName);
}
}
}
Sorry I'm a beginner just starting out using Java and I've encountered this problem
I have two classes, say they are
class Dog {
}
class Cat {
}
then I created an array that is filled up with either one of those two
Object[][] myAnimal = new Object[4][5];
I want to set a variable equal to a random Object from my array, but I don't know which class it came from. Is there any way to do this?
The ideal solution is to create your own superclass, say Animal which has declares abstract methods. For example, you can do:
abstract class Animal {
public abstract void speak();
}
Then Cat and Dog each provide their own implementations for the abstract method:
class Cat {
public void speak() {
System.out.println("Meow!");
}
}
class Dog {
public void speak() {
System.out.println("Woof!");
}
}
Now you can simply declare your array as
Animal[][] myAnimal = new Animal[4][5];
Place some animals in the array:
myAnimal[0][0] = new Dog();
myAnimal[0][1] = new Cat();
And then tell the animals to speak:
myAnimal[0][0].speak();
myAnimal[0][1].speak();
I have left out the syntax for main() here, but I hope you can put this together yourself. The concepts used here are called "polymorphism". I strongly suggest you study up on it to help you use this crucial OO concept when designing your code.
Well, assuming that your array is filled with instances of one of the two classes, you could do something like:
if(myAnimal[x][x] instanceof Dog) //it is an instance of the Dog class
You really shouldn't do things like this especially as a beginner though. You said that you're trying to select a random dog or cat? The better way would be to keep two separate arrays, one for dogs and one for cats. Then you can select a random element from the two arrays and you'll know what class you're dealing with.
Visitor pattern would be really good approach to consider in such situation. Let say, you are making a game that need to react differently for different object (Cat, Dog, Money, etc). So do this:
Make an interface IAnimal that has following definition:
interface IAnimal {
void visit(IAnimalVisitor visitor, Object param);
}
class Cat implements IAnimal {
void visit(IAnimalVisitor visitor, Object param) {
visitor.visit(this, param);
}
}
class Dog implements IAnimal {
void visit(IAnimalVisitor visitor, Object param) {
visitor.visit(this, param);
}
}
The IAnimalVisitor will contain one visit() method for each animal type defined. So it will be like:
interface IAnimalVisitor {
public void visit(Cat c, Object param);
public void visit(Dog c, Object param);
}
Then you could use put your logic to deal with cat and dog as per you want. For example:
class AnimalFeeder implements IAnimalVisitor {
public void visit(Cat c, Object param) {
c.feed(milk);
c.feed(cat_food);
}
public void visit(Dog d, Object param) {
d.feed(dog_food);
}
}
Then you can use above food feeding class to feed to you IAnimal array like this:
IAnimal[] animals = new IAnimal[] { new Cat(), new Dog(),
new Dog(), new Cat() };
IAnimalVisitor feeder = new AnimalFeeder();
for(IAnimal animal : animals) {
animal.visit(feeder, null);
}
You can achieve full freedom to deal with any level of hierarchy within classes. Just put the visit() for each animal class type within IAnimalVisitor.
I think you have to use reflection api, if you want that class instance , its necessary to check any object at runtime ... i think your question is you don't want to put condition static and how to put condition dynamically for different different animal, today its dog,tiger tomrrow its cow or etc... so plz use refelction api
I'm kind of stuck on the following question:
What two Java language mechanisms allow the type of an object reference variable to be "different" than the type of the object to which it refers? Give specific examples to illustrate. In what sense are they not different at all?
My current answer is that it is "implement" and "extend" right? And they are similar because they both will make a class that at least will posses all of the method signatures of the super class which can be actual, abstract, or an interface. Is this correct? Thanks in advance!
That is more or less correct. The second part of your answer should talk about subtyping. In Java, it is not sufficient for objects to just have the same method signatures. There actually has to be a declared subtyping relationship (via extends / implements).
This is not mere pedantry. In some languages (but not Java), the mere existence of compatible method signatures is sufficient for type compatibility. This is called "duck typing".
Implements
interface Animal {
void attackHuman(); // actually public abstract by default
}
class Horse implements Animal {
public void attackHuman() { }; // must implement
}
// type and reference the same
Horse a1 = new Horse();
// type and reference different
Animal a2 = a1;
Extends
class Animal {
void attackHuman();
}
class Dinosaur extends Animal {
// attackHuman() inherited
}
// type and reference the same
Dinosaur a1 = new Dinosaur();
// type and reference different
Animal a2 = a1;
See this example....
- Here the Animal is the Super-Class, and the Dog and Cat are inherited out of it.
- You can Create a Dog object using an Animal Object Reference Variable.
- This is known as Class Polymorphism.
public class Test {
public static void main(String[] args){
Animal a = new Dog();
new Hospital().treatAnimal(a);
}
}
class Animal {
public void sayIt(){
}
}
class Dog extends Animal{
public void sayIt(){
System.out.println("I am Dog");
}
}
class Cat extends Animal{
public void sayIt(){
System.out.println("I am Cat");
}
}
See the NEXT PAGE for the Remaining Code
class Hospital{
public void treatAnimal(Animal a){
if(a instanceof Dog){
a.sayIt(); // Will output "I am Dog"
}
else{
a.sayIt(); // Will output "I am Cat"
}
}
}
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.