13 Replies Latest reply on Oct 16, 2010 10:00 AM by YoungWinston

    method parameters subclass question

    805866
      Hi,
      I'm trying to do this:

      Superclass thing;
      //thing is set to one of two subclasses
      methodName(thing);

      void methodName(Subclass1 a){
      }

      void methodName(Subclass2 a){
      }

      Is there any way I can make it so that java knows to call the appropriate methodName() depending on whether thing is a Subclass1 or a Subclass2?
        • 1. Re: method parameters subclass question
          DrClap
          No. The compiler makes the decision about which overloaded method to call, based on the type of the reference which is used as the parameter.

          But if there's something which should work differently for different subclasses of the (poorly named) Superclass class, then it should be a method of Superclass which is overridden by those subclasses. Not a method of some other class, which is what I think you were asking about.

          However it's impossible to discuss design with classes named "Superclass" and "Subclass1", except in general terms. (Which is what my previous paragraph was.) To have any useful discussion we'd have to have a real use case, not a made-up one. Do you have a real use case for this idea? If so, what is it?
          • 2. Re: method parameters subclass question
            805866
            Yes, I do have a real use case for this. Sorry for doing the made-up one. I am writing a space-invaders type computer game. The player's spaceship, the enemies, the power ups, and the bullets are all subclasses of the GameObject class. GameObject has methods for movement, collision detection, etc. The game keeps a list of all of its GameObjects called myGameObjects. Every frame, it iterates through myGameObjects and calls the checkCollisions(ArrayList<GameObject> all) method of the object. checkCollisions iterates through all of the other game objects and checks if it collides with any of them. If it does collide, it calls a method collision(), to which it will pass the object is is colliding with.

            Every subclass of GameObject I want to be able to have a method like "collision(Enemy e)." In short, if in the Player object, I call "collision(enemy)", where enemy is of the class Enemy, will java know to call the "collision(Enemy e)" method as opposed to, for example, the "collision(Bullet b)" method?

            Sorry if this is not clear.
            • 3. Re: method parameters subclass question
              DrClap
              You didn't say anything about the relationship between Enemy and Bullet. If they have no common superclass except Object (which I'm guessing is the case) then the compiler can perfectly well tell the difference between an Enemy reference and a Bullet reference, and choose the appropriate overloaded method.

              This wouldn't be the case if you were casting an Enemy (or Bullet) object to an Object reference; in that case the compiler wouldn't be able to tell. And you would get a compiler error anyway. But I'm sure you aren't doing that. I'm also making an educated guess that Bullet is not a subclass of Enemy, nor vice versa. That would foul up the compiler's ability to choose an overloaded method, and you would get a compiler error in this case too.
              • 4. Re: method parameters subclass question
                EJP
                Sounds like a job for the Visitor pattern.
                • 5. Re: method parameters subclass question
                  805866
                  Enemy and Bullet are both subclasses of the GameObject class. I want to be able to call "collide(GameObject g)", where g is an Enemy or a Bullet, and have the appropriate method called. I want this because if I ever make this into a game library, I want users to be able to create their own subclasses of GameObject, and all they would have to do to set an action for a collision is implement, for example, a "void collision(Enemy e)" method.
                  • 6. Re: method parameters subclass question
                    805866
                    Here's a simpler example of what I want to do:

                    class Animal {
                    ...
                    void checkCollisions(Animal[] animals){
                    for (Animal a : animals){
                    if (collidesWith(a) && a != this){
                    collision(a);
                    }
                    }
                    }
                    }

                    class Dog {
                    ...
                    void collision(Cat c){
                    println("Ow! I collided with a cat");
                    }
                    }

                    class AnimalProgram {
                    public static void main(String[] args) {
                    Animal[] animals = {new Cat(), new Dog(), new Cow(), new Pig()};
                    Animal fido = new Dog()
                    fido.checkCollisions(animals);
                    }
                    }

                    Output:
                    Ow! I collided with a cat




                    How do I do this?
                    • 7. Re: method parameters subclass question
                      YoungWinston
                      802863 wrote:
                      Every subclass of GameObject I want to be able to have a method like "collision(Enemy e)." In short, if in the Player object, I call "collision(enemy)", where enemy is of the class Enemy, will java know to call the "collision(Enemy e)" method as opposed to, for example, the "collision(Bullet b)" method?
                      Just as a matter of interest, what determines what collides with what? If it's simply whichever GameObject gets read first, I suspect that the methods are going to have be symmetrical, which tends to argue against overriding. If certain collisions are one-way only (ie, a Bullet can collide with an Enemy, but not vice-versa) you may also find some odd logic if you're trying to implement it all by overriding methods.

                      Winston
                      • 8. Re: method parameters subclass question
                        805866
                        Each object takes care of half of the collision. In the collision between Dog and Cat, for example, the Dog might be responsible for barking and the Cat might be responsible for meowing. Also, the reasons why I want to do it this way is so I can make a library.

                        Edited by: 802863 on Oct 15, 2010 5:45 PM
                        • 9. Re: method parameters subclass question
                          796440
                          802863 wrote:
                          Each object takes care of half of the collision. In the collision between Dog and Cat, for example, the Dog might be responsible for barking and the Cat might be responsible for meowing. Also, the reasons why I want to do it this way is so I can make a library.
                          You may want something like this. Again, this is just a rough guess using general principles based on a bare cursory knowledge of your requirements.
                          public interface Collider {
                            void collideWith(Collider c);
                          }
                          
                          public abstract class Animal implements Collider {
                            ...
                          }
                          
                          public class Dog extends Animal {
                            public void collideWith(Collider c) {
                              ...
                            }
                          
                            ...
                          }
                          
                          // Similarly for Cat
                          
                          public class Main {
                            public static void main(String[] args) {
                              Animal a1 = new Cat();
                              Animal a2 = new Dog();
                          
                              a1.collide(a2);
                              a2.collide(a1);
                          }
                          • 10. Re: method parameters subclass question
                            805866
                            Yes, that's exactly what I want to do, but how do I implement "a1.collide(a2)"? Does Cat have a "collide(Dog d)" method?
                            • 11. Re: method parameters subclass question
                              796440
                              802863 wrote:
                              Yes, that's exactly what I want to do, but how do I implement "a1.collide(a2)"?
                              You don't. You implement Cat.collide(Collider) and Dog.collide(Collider).
                              Does Cat have a "collide(Dog d)" method?
                              You could, but then you're right back where you started from. If Cat has to have one behavior when it collides with Dog and a different behavior when it collides with Ferret, then you could do instanceof checks or you could use the Visitor Pattern as suggested. Or perhaps the Command Pattern, where Cat has a Map of classes to implementors of a collide method.

                              Once again, there's very little to go on here that can be used to inform more specific advice.
                              • 12. Re: method parameters subclass question
                                452196
                                The way you'd use the visitor pattern here would be something like:
                                public interface AnimalVisitor {
                                      void visitDog(Dog dog);
                                      void visitCat(Cat cat); // one of these for each subclass of animal
                                      }
                                ,,,
                                
                                public class Animal {
                                   ..
                                  public abstract void accept(AnimalVisitor av);
                                  ..
                                 }
                                
                                
                                
                                public class Dog extends Animal {
                                
                                     public void accept(AnimalVisitor av) {
                                           av.visitDog(this);
                                           }
                                
                                
                                  private void eatCat(Cat cat) {
                                     ....
                                  }
                                
                                  private void sniffBut(Dog otherDog) {
                                   }
                                   public void collideWith(Animal animal) {
                                         animal.accept(new AnimalVisitor() {
                                              
                                                public void visitCat(Cat cat) {
                                                     eatCat(cat);
                                                   }
                                
                                               public void visitDog(Dog dog) {
                                                    sniffBut(dog);
                                                    }
                                                });
                                       }
                                Note once the AnimalVisitor stuff is in place you can use it for many other purposes with differently constituted visitors.

                                Edited by: malcolmmc on 18-Oct-2010 22:49
                                Oops typo
                                • 13. Re: method parameters subclass question
                                  YoungWinston
                                  802863 wrote:
                                  Yes, that's exactly what I want to do, but how do I implement "a1.collide(a2)"? Does Cat have a "collide(Dog d)" method?
                                  In addition to the other good advice, you could also implement a Collision event class that takes two GameObjects. It doesn't solve the business of dispatching, but could help to deal with any other gameboard changes that result from the collision.

                                  Winston