since I assumed that the default class construction implies non-static getters and setters and no static method is provided to the interface. But the question seems to have an assumed part like this:
It code does assume the existing of accessor methods i.e. getXXX and setXXX for each of the three properties of Item class. It contains this line in the code: //accessors not shown
This implies that the accessor methods are there but are not shown here in the code listing.
But the static getter that you've mentioned is not a valid getter method for the price field and is not required to answer the question either.
All options compile and result in the same output, but I am still confused. How Java does allow to invoke an instance method on Item? It's a class name. I thought it would check for a static method getPrice() and result in compiler error since it's not found.
Could you clarify this aspect?
Your understanding about Item::getPrice; is incorrect. Item::getPrice is not an actual call to any method. It is just a reference to the getPrice method of Item class. That this method is static or not has nothing to do with what Item::getPrice means. That is why no instance is required to refer to the getPrice method. Again, you are not calling the getPrice method at this point. You are merely saying that you are going to use the getPrice method of Item class later.
Now, when you say, ToDoubleFunction<Item> priceF = Item::getPrice; you are saying that you will use Item class's getPrice method to implement the ToDoubleFunction<Item> interface. Again, you are not calling the getPrice method yet. Only declaring that the applyAsDouble function (which is what ToDoubleFunction requires you to implement) will use Item class's getPrice method in its body.
Finally, the place when the method is actually invoked is when collect(Collectors.averagingDouble(priceF)). Here, you actually need an object of class Item on which getPrice method can be invoked. This Item object is supplied by the stream which you are iterating over in that call. So when the compiler generates the byte code for this collect call, it knows how to implement the ToDoubleFunction's applyAsDouble method. At this time, it will make use of the fact that getPrice method of Item class is an instance method and it will check whether there is an Item instance available in the context at that time. Indeed, while looping through a collection of Items, every iteration does have a reference to an Item object. Thus, the compiler will generate the body of this function with code that invokes the getPrice method on the reference to the Item object that the loop is currently iterating over.