1

I'm baffled by some source code I'm looking at, and I'm trying to get a better understanding. The code is below, but it is also available at Ideone where you can play with it yourself.

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public interface Fruit {
        public void apple();
    }

    Fruit interfaceFruit;

    public void apple(){
        System.out.println("apple");
        if (interfaceFruit != null) {
            interfaceFruit.apple();
        }
    }

    public void setFruit(Fruit f) {
        interfaceFruit = f;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        Ideone test = new Ideone(){
            @Override
            public void apple() {
                System.out.println("local override of apple");
            }
        };
        System.out.println("1) ---");
        test.apple();

        Ideone test2 = new Ideone();
        System.out.println("2) ---");
        test2.apple();

        test2.setFruit(new Fruit() {
            @Override
            public void apple() {
                System.out.println("interface override of apple");
            }
        });
        System.out.println("3) ---");
        test2.apple();
    }
}

The output is:

1) ---
local override of apple
2) ---
apple
3) ---
apple
interface override of apple

What exactly is going on in this code? There is an interface declared inside of a class (so, an inner interface, right?) and then the interface is declared as an instance variable to the class. This is where I'm confused.

I think what is happening is that if an anonymous inner class is instantiated for the interface Fruit, we are creating an unnamed class that implements the interface. What I'm not totally getting is how or why the interface is stored in an instance variable to the class. What is the purpose of this? What is this practice called? This seems very strange and I'm not really sure what someone would get out of this.

boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52
  • Related: http://stackoverflow.com/questions/71625/why-would-a-static-inner-interface-be-used-in-java – jaco0646 Aug 12 '15 at 20:10
  • 1
    Interface is **not** stored in a variable. The variable is declared as being of the interface **type**. – PM 77-1 Aug 12 '15 at 20:23
  • 1
    It is important to remember about interfaces that nesting for them is only a lexical thing, in other words: nested interfaces are always implicitly `static`. The line you're questioning is simply a field declaration, and is completely independent of the interface declaration. You could move your interface into a separate source file and you could still declare the field to be of type `Fruit`. – biziclop Aug 12 '15 at 20:32

2 Answers2

1

This is not usual code, it is just an exercise so you can see how it works. So yes, things may look "strange".

What I'm not totally getting is how or why the interface is stored in an instance variable to the class

It is not stored, it is defined. You can have inner classes and interfaces defined in a class; a couple of examples:

  • The classes and interfaces are only used in the internal logic of the class and not needed elsewhere; usually those are defined as private. Works more or less the same than an anonymous class.

  • The classes and interfaces are tightly coupled from the class. For example, you define a class and a Comparator implementation for that bean; since such Comparator is only useful for elements of that class, you define that as a nested class. It works just as another level of "packaging".

For example, I am adept to control the values passed to my methods so, when it makes sense, I do things like (very dumb example)

public class Calendar {
   public static enum WeekDay {
     MONDAY,
     ...
     SUNDAY;
  }

  public Date getNextDay(WeekDay weekDay) {
     ...
  }
}

The enum is only useful to access the logic of the class, so it is defined within the class.

And example in the Java API is the java.util.Map.Entry<K,V> class, that is used by Map implementations to give access to the key-value pairs they store.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • Regarding the 'stored vs defined' comment in your answer, I was talking about this line `Fruit interfaceFruit;` The interface is declared as an instance variable no? Then it is set later via the `setFruit()`. As far as you saying, `This is not usual code, it is just an exercise so you can see how it works.` - that makes me feel a little better. I wrote this code, but it was just simplifying what is really in our code base. – boltup_im_coding Aug 12 '15 at 20:17
  • 1
    `The interface is declared as an instance variable no?` No. The interface is fully defined by `interface Fruit {...}`, What `Fruit fruit` does is to *declare a variable* that may reference instance of a class that implements `Fruit` (or null if no value is assigned). – SJuan76 Aug 12 '15 at 20:20
  • 2
    The interface is declared as an inner one, and there is a instance variable of type Fruit declared in the class. Moreover, either if you make it explicit or not, any inner interface is considered a static inner interface. – iullianr Aug 12 '15 at 20:20
  • @iullianr I do not think that `inner interface is considered a static inner interface`. The `Fruit` interface is defined as `Ideone.Fruit` but not the static one. – MaxZoom Aug 12 '15 at 20:35
  • 1
    @MaxZoom, is considered a static interface in the same sense as static inner class. As you also mention by Ideone.Fruit it means you don't need an instance of Ideone, to work with Fruit (also in the code you can declare an anonymous class that implements Fruit without having an instance of Ideone, just like in the case of static inner classes). – iullianr Aug 12 '15 at 20:38
1

The declaration:

Fruit interfaceFruit;

Simply says: "declare the variable interfaceFruit, which will be used to hold a reference to an object that implements Fruit.

Such a variable can hold a reference to any class, provided that it implements the interface. And what you can do with it is access all the methods and constants that are defined in the interface, because Java knows that whatever the class is, it will have overriding methods matching the declarations in Fruit (which, in this case, only has apple()).

This sort of thing is very commonly used in Java. It allows you to use a variable to hold any object that conforms to a contract, but drop in different implementations of it. The practice is called "Programming to an interface". A very common example is declaring a variable like:

List<Integer> list;

(Where List is the interface java.util.List), and then assigning it a particular implementation:

list = new LinkedList<Integer>();
list = new ArrayList<Integer>();
list = Arrays.asList(1,5,8,9);

Whichever class the object you assigned to is (and in Arrays.asList's case, you don't even know which class that would be), it's going to have all the operations that java.util.List defines - such as add() or iterator().

So the same applies to your Fruit interface. The fact that it happens to be a nested interface is not that important.

boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52
RealSkeptic
  • 33,993
  • 7
  • 53
  • 79