2

For practice purposes, I want to achieve the following.

  1. Have simple Interface

  2. Simple class that implements that interface

  3. Make two instances of the class

  4. Store them in collection (ArrayList in this example)

  5. Iterate over the collection calling the method on the class

Interface:

public interface MyInterface {
     void sayHello();
}

Class:

public class Person implements MyInterface{
    private String name;

    public Person(String nameValue) {
        name = nameValue;
    }

    @Override
    public void sayHello() {
        System.out.println(name);
    }
}

Main:

public class DemoApplication {

    public static void main(String[] args) {
        ArrayList<MyInterface> personHolder = new ArrayList();
        MyInterface me = new Person("Myself");
        MyInterface daughter = new Person("Daughter");
        personHolder.add(me);
        personHolder.add(daughter);

        greeter(personHolder);

    }

    static void greeter(ArrayList persons){

        persons.forEach((person -> {

        }));        
    }
}

Now inside the greeter method in the the loop, I was expecting to simply call:

person.sayHello()

But when I inspect the person, I do not see the class method. After some playing around, this piece of code that casts Person seems to work:

((Person) person).sayHello();

Where is my method gone? Why Do I have to cast in order to get it? My background is Javascript, and I kinda expected to have it right there.

Amiga500
  • 5,874
  • 10
  • 64
  • 117
  • You are using raw types: `ArrayList`. Make sure you specify the type argument along with it. E.g. `static void greeter(ArrayList persons)`, or better: `static void greeter(List extends Person> persons)`. – MC Emperor Nov 28 '19 at 13:12

5 Answers5

6

You are using a raw type:

static void greeter(ArrayList persons)

so you can only access methods of the Object class inside persons.forEach.

You should change it to:

static void greeter(List<MyInterface> persons)

Note that I used the List interface instead of the ArrayList implementation, since it's considered better practice to program to interfaces.

Eran
  • 387,369
  • 54
  • 702
  • 768
3

That is what generics are for. Do not use raw types without the generic type. The compiler should have given you a warning about that.

You want

 static void greeter(List<MyInterface> persons){

That way, the compiler knows that persons contains instances of MyInterface and you can call the methods of that interface without class-casting.

Without it, it can only assume that they are Object.

Thilo
  • 257,207
  • 101
  • 511
  • 656
3

change the greeter function and add a generic MyInterface:

static void greeter(ArrayList<MyInterface> persons) {
...
}

Otherwise Java won't knows nothing about what's stored in the array list and thinks that its an Object (because everything is an object). Obviously object doesn't have sayHello method that's why you had to do casting.

Another thing, more a code style - just an advice:

In java we usually work against interface whenever possible, so prefer interface List<MyInterface> over concrete implementation ArrayList<MyInterface> both in "greeter" implementation and in method.

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
2

You missed to add the type of ArrayList while passing the argument. Please try below code.

static void greeter(ArrayList <MyInterface> persons){
    persons.forEach((person -> {
        person.sayHello();
    }));   
 }
0

Change from: static void greeter(ArrayList persons) to: static void greeter(ArrayList persons)

In first way we are using generics ArrayList that is not displaying what kind of object that has. In second way we are explicating that ArrayList must have objects of MyInterface type So now that will show the method sayHello in that ArrayList as well.