Search code examples
javainterfacerunnableanonymous-class

Extending an Interface vs Instantiating via Anonymous Class


NOTE: I am aware that this is dangerously close to many other questions. I haven't seen any, however, that do not pertain specifically to Android's OnClickListener interface. I am asking in a general sense.

I understand the difference between instantiating an interface via an anonymous class... a la:

private final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        draw();
    }

};

... and extending the interface.

public class ClassyClass implements Runnable {
    ...
    //do other cool stuff here
    ...
    @Override
    public void run() {
        draw();
    }
    ...
    //and more here
    ...

}

But, other than the obvious benefits from interfaces such as OnClickListener is there a strong advantage to either option?

I would think that extending it would be the obvious choice because you are already creating that object - no duplication of effort. Is this right?

I am asking in a general sense but, as I am currently working with Runnable, if it has sees an advantage from either option I'd love to know.


Solution

  • Well here is an example that shows the main differences. It's a little contrived but it's just to illustrate.

    Here is an anonymous version:

    class PrintBuilder {
        List<Runnable> printers = new LinkedList<>();
    
        List<Runnable> get() {
            return printers;
        }
    
        PrintBuilder add(final String line) {
            printers.add(new Runnable() {
                public void run() {
                    System.out.println(line);
                }
            });
    
            return this;
        }
    }
    

    Here is a nested version:

    class PrintBuilder {
        List<Printer> printers = new LinkedList<>();
    
        PrintBuilder add(String line) {
            printers.add(new Printer(line));
            return this;
        }
    
        List<Printer> get() {
            return printers;
        }
    
        static class Printer implements Runnable {
            String line;
    
            Printer(String line) {
                this.line = line;
            }
    
            public void run() {
                System.out.println(line);
            }
        }
    }
    

    So you can see the main differences are then:

    • An anonymous class is inner and it has an implicit reference to the enclosing instance.

    In particular, in the above example, the PrintBuilder is leaked until the inner Runnable objects die. In the second example, the Runnable class is static so it doesn't have this problem.

    • Anonymous classes are a little bit shorter.

    An anonymous class doesn't need fields and constructors because they are implicit.

    • Big difference in the way the code is organized.

    An anonymous class is declared where it's instantiated and this can be pretty destructive to the layout of the enclosing class if the anonymous class isn't very short. On the other hand if the anonymous class is short, the functional-like syntax is nice.

    Also all classes tend to grow and in my experience this can turn in to a smell when an anonymous class gets too big. Anonymous classes are also much more difficult to refactor in to a top-level class.