Calling methods from objects which implement an interface - java

I am trying to wrap my head around interfaces, and I was hoping they were the answer to my question.
I have made plugins and mods for different games, and sometimes classes have onUpdate or onTick or other methods that are overridable.
If I make an interface with a method, and I make other classes which implement the method, and I make instances of the classes, then how can I call that method from all the objects at once?

You'll be looking at the Observer pattern or something similar. The gist of it is this: somewhere you have to keep a list (ArrayList suffices) of type "your interface". Each time a new object is created, add it to this list. Afterwards you can perform a loop on the list and call the method on every object in it.
I'll edit in a moment with a code example.
public interface IMyInterface {
void DoSomething();
}
public class MyClass : IMyInterface {
public void DoSomething() {
Console.WriteLine("I'm inside MyClass");
}
}
public class AnotherClass : IMyInterface {
public void DoSomething() {
Console.WriteLine("I'm inside AnotherClass");
}
}
public class StartUp {
private ICollection<IMyInterface> _interfaces = new Collection<IMyInterface>();
private static void Main(string[] args) {
new StartUp();
}
public StartUp() {
AddToWatchlist(new AnotherClass());
AddToWatchlist(new MyClass());
AddToWatchlist(new MyClass());
AddToWatchlist(new AnotherClass());
Notify();
Console.ReadKey();
}
private void AddToWatchlist(IMyInterface obj) {
_interfaces.Add(obj);
}
private void Notify() {
foreach (var myInterface in _interfaces) {
myInterface.DoSomething();
}
}
}
Output:
I'm inside AnotherClass
I'm inside MyClass
I'm inside MyClass
I'm inside AnotherClass
Edit: I just realized you tagged it as Java. This is written in C#, but there is no real difference other than the use of ArrayList instead of Collection.

An interface defines a service contract. In simple terms, it defines what can you do with a class.
For example, let's use a simple interface called ICount. It defines a count method, so every class implementing it will have to provide an implementation.
public interface ICount {
public int count();
}
Any class implementing ICount, should override the method and give it a behaviour:
public class Counter1 implements ICount {
//Fields, Getters, Setters
#Overide
public int count() {
//I don't wanna count, so I return 4.
return 4;
}
}
On the other hand, Counter2 has a different oppinion of what should count do:
public class Counter2 implements ICount {
int counter; //Default initialization to 0
//Fields, Getters, Setters
#Overide
public int count() {
return ++count;
}
}
Now, you have two classes implementing the same interface, so, how do you treat them equally? Simple, by using the first common class/interface they share: ICount.
ICount count1 = new Counter1();
ICount count2 = new Counter2();
List<ICount> counterList = new ArrayList<ICount>();
counterList.add(count1);
counterList.add(count2);
Or, if you want to save some lines of code:
List<ICount> counterList = new ArrayList<ICount>();
counterList.add(new Counter1());
counterList.add(new Counter2());
Now, counterList contains two objects of different type but with the same interface in common(ICounter) in a list containing objects that implement that interface. You can iterave over them and invoke the method count. Counter1 will return 0 while Counter2 will return a result based on how many times did you invoke count:
for(ICount current : counterList)
System.out.println(current.count());

You can't call a method from all the objects that happen to implement a certain interface at once. You wouldn't want that anyways. You can, however, use polymorphism to refer to all these objects by the interface name. For example, with
interface A { }
class B implements A { }
class C implements A { }
You can write
A b = new B();
A c = new C();

Interfaces don't work that way. They act like some kind of mask that several classes can use. For instance:
public interface Data {
public void doSomething();
}
public class SomeDataStructure implements Data {
public void doSomething()
{
// do something
}
}
public static void main(String[] args) {
Data mydataobject = new SomeDataStructure();
}
This uses the Data 'mask' that several classes can use and have certain functionality, but you can use different classes to actually implement that very functionality.

The crux would be to have a list that stores every time a class that implements the interface is instantiated. This list would have to be available at a level different that the interface and the class that implements it. In other words, the class that orchestrates or controls would have the list.
An interface is a contract that leaves the implementation to the classes that implements the interface. Classes implement the interface abide by that contract and implement the methods and not override them.
Taking the interface to be
public interface Model {
public void onUpdate();
public void onClick();
}
public class plugin implements Model {
#Override
public void onUpdate() {
System.out.println("Pluging updating");
}
#Override
public void onClick() {
System.out.println("Pluging doing click action");
}
}
Your controller class would be the one to instantiate and control the action
public class Controller {
public static void orchestrate(){
List<Model> modelList = new ArrayList<Model>();
Model pluginOne = new plugin();
Model plugTwo = new plugin();
modelList.add(pluginOne);
modelList.add(plugTwo);
for(Model model:modelList){
model.onUpdate();
model.onClick();
}
}
}
You can have another implementation called pluginTwo, instantiate it, add it to the list and call the methods specified by the interface on it.

Related

Inner class seems unnecessary in the example given in On Java 8 by Bruce Eckel

Bruce Eckel gives the following example in Chapter Inner Classed of the book On Java 8 to demonstrate the necessity of using an inner class instead of implementing an interface. But I found the code works fine without the inner class. The code seems to compile and give the same result if you just implement the Incrementable interface for Callee2. Does Bruce Eckel gives an inappropriate example or do I miss something?
package innerclasses;
interface Incrementable {
void increment();
}
// Very simple to just implement the interface:
class Callee1 implements Incrementable {
private int i = 0;
#Override
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement {
public void increment() {
System.out.println("Other operation");
}
static void f(MyIncrement mi) {
mi.increment();
}
}
// If your class must implement increment() in
// some other way, you must use an inner class:
//Why not just implement Incremetable??? I don't get it
class Callee2 extends MyIncrement {
private int i = 0;
#Override
public void increment() {
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
#Override
public void increment() {
// Specify outer-class method, otherwise
// you'll get an infinite recursion:
Callee2.this.increment();
}
}
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {
callbackReference = cbh;
}
void go() {
callbackReference.increment();
}
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
Output:
Other operation
1
1
2
Other operation
2
Other operation
3
Why not just implement the Incrementable interface for class Callee2? I tried that and it seems to work out fine.
...
class Callee2 extends MyIncrement implements Incrementable{
...
// everything remains the same just comment out the inner class
// closure
}
In the book Bruce Eckel says:
This shows a further distinction between implementing an interface in an outer class versus doing so in an inner class. Callee1 is clearly the simpler solution in terms of the code. Callee2 inherits from MyIncrement, which already has a different increment() method that does something unrelated to the one expected by the Incrementable interface. When MyIncrement is inherited into Callee2, increment() can’t be overridden for use by Incrementable, so you’re forced to provide a separate implementation using an inner class.
I didn't see why I'm forced to use inner class since implementing the interface provides the exact same output. Could you please explain how the code may behave differently without the inner class?

Is forcing a constructor signature a valid reason to use an abstract class rather than an interface?

For a project, I have written the following interface:
public interface IManipulation {
void applyManipulation (double value);
}
Since I would like to force all implementing classes to use a certain constructor signature, I have been considering to change the interface into something like the following abstract class:
(edit: I forgot that it's not possible to have an abstract constructor, so I changed the "solution" below a bit)
public abstract class Manipulation {
private Signal signal;
public Manipulation (Signal signal) {
this.signal = signal;
}
public abstract void applyManipulation (double value);
protected Signal getSignal () {
return signal;
}
}
The reason for wanting to force this constructor is because every implentation should have an instance of Signal available. (and it should not be possible to reassign this signal)
Is this a valid reason to replace the interface with an abstract class (and live with the limitations that come with it), or are there any other potential solutions?
instead of an abstract class you should use an init method for that purpose.
public interface MyInterface{
public void init(YourParam p);
//... other methods
}
in the init you check, if the class is allready initialised if yes, just return.
So you have still an interface and can extend from other classes.
Instead of the constructor you will call the init method for your initialization
EDIT:
public interface IManipulation {
void init(Signal s);
void applyManipulation (double value);
}
You should use abstract classes only, if you have implementation details in it, which are shared by all subclasses. For Method signatures use interfaces
You can make empty constructor private in the abstract class:
abstract class AbstractManipulation {
private final Integer signal;
private AbstractManipulation() {
signal = null;
}
public AbstractManipulation (Integer signal) {
this.signal = signal;
}
}
class Manipulation extends AbstractManipulation {
public Manipulation(Integer signal) {
super(signal);
}
// Cannot redeclare
//public Manipulation() {
//}
}
Then:
public static void main(String[] args) {
// Will not work
//Manipulation m = new Manipulation();
// This one will
Manipulation m = new Manipulation(1);
}
You should not choose for technical reasons but rather logical, ie an abstract class is used when you have a realtion with the sub-classes like for example person: student, teacher. An interface is used when you want to impose a service contract for classes that may not have a relationship between them.

Visitor pattern implementation in case of source code un-availability

One of the reasons to consider the Visitor_pattern:
A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures.
Assume that you don't have the source code of third party libraries and you have added one operation on related objects.
Since you don't have object, your elements (Third party classes) can't be modified to add Visitor.
In this case, double dispatch is not possible.
So which option is generally preferred?
Option 1: Extend one more inheritance hierarchy on top of third party class and implement pattern as show in picture with double dispatch?
For a given hierarchy of Class B which extends Class A, I will add
ElementA extends A
ElementB extends B
Now ConcreteElements are derived from ElementA instead of class A.
Cons: The number of classes will grow.
Option 2: Use Visitor class a central helper class and get the work done with single dispatch.
Cons: We are not really following Visitor patter as per UML diagram.
Correct if I am wrong.
You could combine a Wrapper and Visitor to solve your problems.
Using the wrapper to add a visit method allows you to increase the usability of these objects. Of course you get the full advantages (less dependency on the legacy classes) and disadvantages (additional objects) of a wrapper.
Here's a worked-up example in JAVA (because it is pretty strict, does not do double-dispatch by itself, and I'm quite familiar with it):
1) Your legacy Objects
Assuming you have your legacy objects Legacy1 and Legacy2which you cannot change, which have specific business methods:
public final class Legacy1 {
public void someBusinessMethod1(){
...
}
}
and
public final class Legacy2 {
public void anotherBusinessMethod(){
...
}
}
2) Prepare the Wrapper
You just wrap them in a VisitableWrapper which has a visit method that takes your visitor, like:
public interface VisitableWrapper {
public void accept(Visitor visitor);
}
With the following implementations:
public class Legacy1Wrapper implements VisitableWrapper {
private final Legacy1 legacyObj;
public Legacy1Wrapper(Legacy1 original){
this.legacyObj = original;
}
public void accept(Visitor visitor){
visitor.visit(legacyObj);
}
}
and
public class Legacy2Wrapper implements VisitableWrapper {
private final Legacy2 legacyObj;
public Legacy2Wrapper(Legacy2 original){
this.legacyObj = original;
}
public void accept(Visitor visitor){
visitor.visit(legacyObj);
}
}
3) Visitor, at the ready!
Then your own Visitors can be set to visit the wrapper like so:
public interface Visitor {
public void visit(Legacy1 leg);
public void visit(Legacy2 leg);
}
With an implementation like so:
public class SomeLegacyVisitor{
public void visit(Legacy1 leg){
System.out.println("This is a Legacy1! let's do something with it!");
leg.someBusinessMethod1();
}
public void visit(Legacy2 leg){
System.out.println("Hum, this is a Legacy 2 object. Well, let's do something else.");
leg.anotherBusinessMethod();
}
}
4) Unleash the power
Finally in your code, this framework would work like this:
public class TestClass{
// Start off with some legacy objects
Legacy1 leg1 = ...
Legacy2 leg2 = ...
// Wrap all your legacy objects into a List:
List<VisitableWrapper> visitableLegacys = new ArrayList<>();
visitableLegacys.add(new Legacy1Wrapper(legacy1));
visitableLegacys.add(new Legacy2Wrapper(legacy2));
// Use any of your visitor implementations!
Visitor visitor = new SomeLegacyVisitor();
for(VisitableWrapper wrappedLegacy: visitableLegacys){
wrappedLegacy.accept(visitor);
}
}
The expected output:
This is a Legacy1! let's do something with it!
Hum, this is a Legacy 2 object. Well, let's do something else.
Drawbacks:
Quite a lot of boilerplate. Use Lombok if you develop in Java.
Quite a lot of wrapper objects instances. May or may not be a problem for you.
You need to know the specific type of the objects beforehand. This implies you know their subtype, they aren't bundles in a List. If that's the case, you have no other option but to use reflection.
There should be a possibility to add new functionality to the classes of some hierarchy, without changing the base class interface. Kinds of possible behavior should be constant, while operations for different classes should execute differently.
The Visitor Pattern allows to concentrate all that operations in one class. There might be a lot of Concrete Element classes (from the diagram), but for each of them there will be implemented visit() method in Concrete Visitor class that will define his own algorithm.
Definition and implementation of method for each subclass of Element class:
public interface Visitor {
void visit(Element element);
}
public class ConcreteVisitor implements Visitor {
public void visit(Element element) {
// implementation
}
}
The Visitor Pattern is easily extended for new operations by implementing this interface by new class with his method implementation.
The following structure encapsulates the Element class:
public lass ObjectStructure {
private Element element;
// some methods
}
This ObjectStructure class could aggregate one or several instances of Element. Presentation that Visitor acts on:
public interface Element {
void accept(Visitor visitor);
}
And implementation of accept() method in the concrete entity:
public class ConcreteElement implements Element {
public void accept(Visitor visitor) {
visitor.visit();
}
}
Using of Visitor Pattern allows to save Element hierarchy from huge logical functionality or complicated configuration.
It is desirable to add the functionality to all the classes of hierarchy while defining a new Visitor subclasses. But there could be a problem: visit() should be overriden for every hierarchy type. To avoid this it's better to define AbstractVisitor class and all leave his all visit() method bodies empty.
Conclusion: using this pattern is good when class hierarchy of type Element keeps constant. If new classes add, it usually goes to considerable changes in classes of Visitor type.
My answer is very similar to Michael von Wenckstern's, with the improvements that we have a named accept method (more like the standard pattern) and that we handle unknown concrete classes -- there's no guarantee that at some point a concrete implementation we haven't seen before won't appear on the classpath.
My visitor also allows a return value.
I've also used a more verbose name for the visit methods -- including the type in the method name, but this isn't necessary, you can call them all visit.
// these classes cannot be modified and do not have source available
class Legacy {
}
class Legacy1 extends Legacy {
}
class Legacy2 extends Legacy {
}
// this is the implementation of your visitor
abstract class LegacyVisitor<T> {
abstract T visitLegacy1(Legacy1 l);
abstract T visitLegacy2(Legacy2 l);
T accept(Legacy l) {
if (l instanceof Legacy1) {
return visitLegacy1((Legacy1)l);
} else if (l instanceof Legacy2) {
return visitLegacy2((Legacy2)l);
} else {
throw new RuntimeException("Unknown concrete Legacy subclass:" + l.getClass());
}
}
}
public class Test {
public static void main(String[] args) {
String s = new LegacyVisitor<String>() {
#Override
String visitLegacy1(Legacy1 l) {
return "It's a 1";
}
#Override
String visitLegacy2(Legacy2 l) {
return "It's a 2";
}
}.accept(new Legacy1());
System.out.println(s);
}
}
First I had to made a few assumptions about the legacy code, since you didn't provide much details about it. Let's say I need to add a new method to Legacy without reimplementing everything. This is how I'll do it:
public interface LegacyInterface {
void A();
}
public final class LegacyClass implements LegacyInterface {
#Override
public void A() {
System.out.println("Hello from A");
}
}
First extends the "contract"
public interface MyInterface extends LegacyInterface {
void B();
}
And implement it in a "decorated" way
public final class MyClass implements MyInterface {
private final LegacyInterface origin;
public MyClass(LegacyInterface origin) {
this.origin = origin;
}
#Override
public void A() {
origin.A();
}
#Override
public void B() {
System.out.println("Hello from B");
}
}
The key point is MyInterface extends LegacyInterface: this is the guarantee the implementations will benefit from both the services from the legacy code and your personnal addings.
Usage
MyInterface b = new MyClass(new LegacyClass());
I think the best approach is the Option 1: Extend one more inheritance hierarchy on top of third party class and implement the visitor pattern with double dispatch.
The problem is the number of additional classes you need, but this can be resolved with a dynamic wrapper decorator.
The Wrapper Decorator is a way to add interface implementation, methods and properties to already existing obejcts: How to implement a wrapper decorator in Java?
In this way you need your Visitor interface and put there the visit(L legacy) methods:
public interface Visitor<L> {
public void visit(L legacy);
}
In the AcceptInterceptor you can put the code for the accept method
public class AcceptInterceptor {
#RuntimeType
public static Object intercept(#This WrappedAcceptor proxy, #Argument(0) Visitor visitor) throws Exception {
visitor.visit(proxy);
}
}
The WrappedAcceptor interface defines the method to accept a visitor and to set and retrieve the wrapped object
interface WrappedAcceptor<V> {
Object getWrapped();
void setWrapped(Object wrapped);
void accept(V visitor);
}
And finally the utility code to create the Wrapper around any obect:
Class<? extends Object> proxyType = new ByteBuddy()
.subclass(legacyObject.getClass(), ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC)
.method(anyOf(WrappedAcceptor.class.getMethods())).intercept(MethodDelegation.to(AcceptInterceptor.class))
.defineField("wrapped", Object.class, Visibility.PRIVATE)
.implement(WrappedAcceptor.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
WrappedAcceptor wrapper = (WrappedAcceptor) proxyType.newInstance();
wrapper.setWrapped(legacyObject);
If your library does not has accept methods you need to do it with instanceof. (Normally you do twice single-dispatching in Java to emulate double dispatching; but here we use instanceof to emulate double dispatching).
Here is the example:
interface Library {
public void get1();
public void get2();
}
public class Library1 implements Library {
public void get1() { ... }
public void get2() { ... }
}
public class Library2 implements Library {
public void get1() { ... }
public void get2() { ... }
}
interface Visitor {
default void visit(Library1 l1) {}
default void visit(Library2 l2) {}
default void visit(Library l) {
// add here instanceof for double dispatching
if (l instanceof Library1) {
visit((Library1) l);
}
else if (l instanceof Library2) {
visit((Library2) l);
}
}
}
// add extra print methods to the library
public class PrinterVisitor implements Visitor {
void visit(Library1 l1) {
System.out.println("I am library1");
}
void visit(Library2 l2) {
System.out.println("I am library2");
}
}
and now in any method you can write:
Library l = new Library1();
PrinterVisitor pv = new PrinterVisitor();
pv.visit(l);
and it will print to you "I am library1";

Java: share object reference without passing as parameter

I have an ObjectFactory and a specialized case of implementation of that factory. I can't change the interface, that has 0 argument.
In one of the implementation I have to read a file and load some data. To pass the filename I can use the system properties because all I need to share is a string.
But in the other implementation I must start not from a file but from a memory structure. How can I do to pass the object (then I think the object reference) to the factory? Other methods? No way I serialize the object on a file and after I read it again because what I want to avoid is right the I/O footprint.
Thanks
OK, more informations:
This is the interface and the abstract factory I have to implement
public abstract interface A
{
public abstract Set<Foo> getFoo();
public abstract Set<Bar> getBar();
}
//this is otherpackage.AFactory
public abstract class AFactory
{
public static AccessFactory newInstance()
{
return a new built instance of the factory
}
public abstract A newA();
}
This is my implementation with my problem:
public class AFactory extends otherpackage.AFactory
{
#Override
public Access newA()
{
return new AA();
}
}
public class AA implements A
{
protected AA()
{
this.objectReferenceIWantToSaveHere = I retrieve from the shared memory zone;
use the object
}
}
Now I'd like to do something like this:
B b = something I built before
save b in a shared memory zone or something like that
otherpackage.AFactory f = mypackage.AccessFactory.newInstance();
A a = f.newA();
And inside the f.newA() call I'd like to access to the b object
Can't you simply use a constructor?
interface ObjectFactory { Object create(); }
class SpecialFactory implements ObjectFactory {
private final Object data;
public SpecialFactory(Object data) { this.data = data; }
#Override public Object create() { return somethingThatUsesData; }
}
Ass assylias proposes, you can pass the reference to the constructor. Or if you know where to find the reference, you could just ask for it before you use it? E.g. data = dataBank.giveMeTheData()
Agree it would help to get some more context around what you are doing... but could you use a shared static class in which your calling code places info into the static class, and your interface implementation references this same static class to obtain either the object and/or instructions?
So here's a client class. It has the entry point..and wants to pass an object to the interface implementer but it can't pass it directly...So it set's object it wants to pass in the MyStaticHelper.SetSharedObject method.
public class Client {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String mySharedObject = "Couldbeanyobject, not just string";
// Set your shared object in static class
MyStaticHelper.SetSharedObject(mySharedObject);
InterferfaceImplementer myInterfaceImplementer = new InterferfaceImplementer();
//
myInterfaceImplementer.RunMyMethod();
}
Here is the code for the static helper...
public class MyStaticHelper {
private static Object _insructionsObject;
public static void SetSharedObject(Object anObject)
{
_insructionsObject = anObject;
}
public static Object GetSharedObject()
{
return _insructionsObject;
}
}
and finally the the class that you call that uses the static helper to get the same object.
public class InterferfaceImplementer {
// no objects
public void RunMyMethod()
{
System.out.println(MyStaticHelper.GetSharedObject());
}
}
Again this works in a very simple scenario and wouldn't stand up if more than one implementer needs to be called simultaneously as this solution would only allow one obj to be in the static helper class.

Interface Method Called in Class Constructor

Could someone explain in the following example why the interface method can be called directly when it is passed as a parameter in a class constructor? I try to search a rule in the Java language specification but can not find one.
public interface Interface {
public void foo();
}
public class Main {
public Main() {}
public Main(Interface obj) {obj.foo();}
public static int test() {return 123;}
}
Is just a polymorphic behaviour, Java expects an implementation of the method of that interface.
That means, any class which implements that method is an Interface, so you can have many many different implementations of that method.
Let's say:
public class ImplementedInterface implements Interface
{
public void foo()
{
System.out.println("Hey!, i'm implemented!!");
}
}
So when you call:
Interface aux = new ImplementedInterface();
Main m = new Main(aux);
The text "Hey!, i'm implemented!!" will be printed.
You can call foo method from Interface reference because it can hold only object of class that implements Interface, so it will provide body for foo method.
Now thanks to late binding Java will use code of object class when needed.
I think that you are confused, you think cuase it's Interface type it's an interface
public Main(Interface obj) {
obj.foo();
}
obj is an object from a concrete implementation of Interface.
You may want to see some common design pattern that take this approach such as Strategy Pattern
For example :
public interface Searcher {
void search(String text, List<String> words);
}
public class BinarySearcher implements Searcher{
#Override
public void search(String text , List<String> words){
//code here
}
}
public class LinearSearcher implements Searcher{
#Override
public void search(String text ,List<String> words ){
// code here
}
}
public class WordContext {
private Searcher searcher;
private List<String> words;
public void makeSearch(String text){
searcher.search(); // you only know at runtime what subtype will be searcher
}
// here you inject by contract
public void setSearcher(Searcher searcher){
this.searcher= searcher;
}
// here you inject by contract
public void setWords(List<String> words){
this.words = words;
}
}
That's the main advantage you guide by abstract contract instead of concrete implementation.
In this example you can change the searcher injecting it, can be a linearSearcher or a binarySearcher, that's the polymorphic magic!
Here is where Programming to an interface, not an implementation comes into play. Your method is expecting an object of the class that that implements the interface
I would explain it with an example.
Let us say I have
LinkedList<String> ll = new LinkedList<String>();
and I have
ArrayList<String> al = new ArrayList<String>();
Now I have a method -
public void deleteFirst(List aList) {
System.out.println(aList.remove(0));
}
Now you can pass both ll and al to the deleteFirst method. Which means your method is passed an object of the class that that implements the interface.
In the example ArrayList and LinkedList both implement the List interface and therefore can be passed to the method. Ultimately what your method is getting is an object of the class that implements the List interface.

Categories