How do I call a method on all objects in an ArrayList?

So, I have the interface Pet

shown below:

public interface Pet{
    void Eat();
}

      

What is implemented:

public class Puppies implements Pet {
    @Override
    public void Eat() {
        // Something gets eaten here, presumably
    }
}

      

and

public class Kittens implements Pet {
    @Override
    public void Eat() {
        // Everybody knows Kittens eats something different
    }
}

      

Hope I did the following, create ArrayList

new pets:

public class PetList{

    public PetList(){
        ArrayList pets = new ArrayList<Pet>();

        Puppies spot = new Puppies();
        Puppies rex = new Puppies();
        Kittens meowth = new Kittens();

        pets.add(spot);
        pets.add(rex);
        pets.add(meowth);
    }

public static void main(String[] args){
    // No idea how to handle this bit
}

      

What I want to do next is go through and tell all my pets to eat. How should I do it?

+3


source to share


5 answers


The main problem with your current code is that ArrayList

( pets

) is a local constructorPetList

, which means you cannot access outside of the class constructor PetList

.

So, first make ArrayList

as an instance variable of the class PetList

so that it can be accessed via the object even outside the constructor .

Then you can provide a method eatAll()

that iterates ArrayList<Pet>

and calls the method eat()

on all objects pet

.

You can link to the code below and follow the inline comments:

public class PetList{
    private List<Pet> pets;//now this is an instance variable

    public PetList(){
        this.pets = new ArrayList<Pet>();//this list is not local now
        Puppies spot = new Puppies();
        Puppies rex = new Puppies();
        Kittens meowth = new Kittens();
        pets.add(spot);
        pets.add(rex);
        pets.add(meowth);
    }

    public void eatAll() { //method to invoke eat() on list of pets
        for(Pet pet : this.pets) { //iterate the pets list
            pet.eat();//call eat() on each pet object
        }
    }

    public static void main(String[] args){
          PetList petList = new PetList();
          petList.eatAll();//invoke the eatAll() method
     }
}

      




As a side note, I highly recommend you follow the Java naming standards ( eat()

should be eat()

, that is, method names should start with lowercase) and consider renaming PetList

class toPetsTesting

(or whatever) to make it more intuitive for developers.

Last but not least, do not assign objects directly to specific class classes such as ArrayList<Pet> pets = new ArrayList<>();

or Puppies spot = new Puppies();

.

The best practice is that you need to assign objects to interface types List<Pet> pets = new ArrayList<Pet>();

or Pet spot = new Puppies();

(which is called code for interface types )

+6


source


public static void main(String[] args){
    pets.foreach(pet::eat);
}

      



Should make everyone eat

+4


source


What is implemented:

In fact, you need to implement an interface, this is not enough to define methods in concrete classes. This is how you do it:

public class Kittens implements Pet {}

      

Since you have an interface, let the type of your instance be Pet, so instead of

Puppies spot = new Puppies();

      

which would be

Pet spot = new Puppies ();

I suggest exploring / continuing to learn the basics of Java (Inheritance, Polymorphism and other concepts).

Here's what you need to get it to work as you expect:

Pet.java

public interface Pet {
    void eat();
}

      

Kettens.java

public class Kittens implements Pet {
    @Override
    public void eat() {
        System.out.println("Everybody knows Kittens eats something different");
    }
}

      

Puppies.java

public class Puppies implements Pet {
    @Override
    public void eat() {
        System.out.println("Something gets eaten here, presumably");
    }
}

      

PetList.java

import java.util.ArrayList;
import java.util.List;

public class PetList {
    public static void main(String[] args) {
        Pet spot = new Puppies();
        Pet rex = new Puppies();
        Pet meowth = new Kittens();

        List<Pet> pets = new ArrayList<>();
        pets.add(spot);
        pets.add(rex);
        pets.add(meowth);

        PetList.feadPets(pets);
    }

    public static void feadPets(List<Pet> pets) {
        for (Pet p : pets) {
            p.eat();
        }
        // Java 8 / Stream syntax.
        // pets.forEach(Pet::eat);
    }
}

      

+2


source


The problem with your current approach is ArrayList pets

only limiting the constructor, so main

cannot access it.

This is how you fix it

public class PetList {

    List<Pet> pets; // should be private, though

    public PetList() {
        this.pets = new ArrayList<Pet>();
    }

      

And in the main

// Should be using a getter, though
for (Pet pet : new PetList().pets) {
    pet.eat();
}

      


Another suggestion

1) Create multiple List<Pet>

(or make your whole class itself a list)
2) Iterate it and call this shared interface method

public class PetList extends ArrayList<Pet> {

    public PetList() {
        add(new Puppy());
        add(new Kitten());
    }

    public static void main(String[] args) {
        PetList pets = new PetList();

        for (Pet pet : pets) {
            pet.eat();
        }
    }
}

      

+1


source


javaguy provided the answer you may have been looking for, but since you seem to be new to this question, there are some more tips for your code:

If you want Java to recognize your class Puppies

as an implementation of your interface Pet

, you must explicitly state this in your class definition:

public class Puppies implements Pet

      

In your class, PetList

you initialize (i.e. create) your list and pets variables in a so called constructor. This means that these variables are not available unless you create an object of this class. You might want to find a guide on how to deal with installing classes. For now, I propose the following solution, instead of writing a subclass and initializing variables there, do it in your method main

:

import java.util.ArrayList;
public class PetList{
    public static void main(String[] args){

        //Initialize the pet list
        ArrayList pets = new ArrayList<Pet>();
        Puppies spot = new Puppies();
        Puppies rex = new Puppies();
        Kittens meowth = new Kittens();
        pets.add(spot);
        pets.add(rex);
        pets.add(meowth);

      

To feed the animals, you can iterate over the list using a for-each-loop. (You should watch this too)

        //Feed the animals
        for(Pet p: pets){
            System.out.println("Serving a meal.")
            p.Eat();
        }

      

[Please also read the last point in the style guide below, as this code will not compile.] Quick introduction: This construct iterates, i.e. loops through all the elements in a variable pets

and stores them, one at a time, in a local variable p

. Inside the brackets, you can perform any operation on this variable, in this case call a method on it Eat()

. See what the console outputs if you added methods System.out.…

and in your Eat()

add animalsSystem.out.println("Kittens just ate.");

Since you are using ArrayList

here, you can also access individual pets through their index, i.e. position in the list. Using a for loop:

        //Feed the animals once more
        for(int i=0; i<pets.size(); i++){ // For each i which is greater or equal to zero and less than the size of pets,
            pets.get(i).Eat();  //Feed the animal in the i-th position in pets
        }

      

Quick style guide

  • Class names must be singular, eg. Puppy

    instead of Puppies

    .
  • Method names should not be capitalized, for example. Eat()

    insteadEat()

  • You can specify ArrayList

    (and basically any other container) what data you will enter into it. This improves type safety because it can check for errors that will still be obvious if you run your code and it crashes.

Suppose you had another class for trees: public class Tree { /* No Eat() method! */}

Since your code is standing now, it would be possible, but fail:

Tree tree = new Tree();
pets.add(tree);
for(Pet p: pets){
    p.Eat(); // Will crash if p reaches the tree.
}

      

But if you parameterize your PetList

like this

ArrayList<Pet> pets = new ArrayList();
Tree tree = new Tree();
pets.add(tree);

      

Java might detect the tree as odd to add to the list of pets. (Actually, Java won't compile the first instance, but I think this is a good approach to type safety.)

+1


source







All Articles