/** Note: All the classes are grouped together here for simplicity. * Java can only have one public class per file (which must be named the same * as the file, but may have many non-public classes that are accessible to all * members of the enclosing package. */ package Generics; /** * Interfaces simply describe the methods that all implementing class must * support. An interface is a class that describes the parameter and return types * of various methods, but does not actually implement them. * * @author Adam J. Conover */ public interface Food { /** All food has calories. */ public float getTotalCalories(); /** All Food comes from someplace. */ public String getHabitat(); } /** * The top level class which implements Food and is Comparable to other Fruits. * The class is abstract because -- without knowing more about the type of fruit -- * We can really know any of the specifics necessary to construct an instance * of the class. * * @author Adam J. Conover */ abstract class Fruit implements Food, Comparable { float calories; // calories per gram float grams; // weight in grams public Fruit(float weightInGrams) { this.grams = weightInGrams; } public float getTotalCalories() { return this.calories * this.grams; } public int compareTo(Fruit obj) { // Use Float objects, so we can use the prebuilt comparator. // Otherwise we would have to create determin the return value ourselves. Float cal1 = this.calories * this.grams; Float cal2 = obj.calories * obj.grams; // Compare the two floats and return the result. return cal1.compareTo(cal2); } } /** * An apple is a type of fruit with it own properties, but there are many varieties * of apple. So, the class is abstract and we rely on derived classes to provide * the specifics of the type of apple. * * @author Adam J. Conover */ abstract class Apple extends Fruit { public Apple(float weightInGrams) { super(weightInGrams); super.calories = .47f; } public String getHabitat() { return "Temperate"; } } /** * Assume specific varieties of fruits originated in specific locations. But these * don't have to be the same place they actually grow. So we should be able the * "getOrigin()" of the specific varieties. * * @author Adam J. Conover */ interface Origin { public String getOrigin(); } /** * A specific variety of Apple... * @author Adam J. Conover */ class Fuji extends Apple implements Origin { public Fuji(float weightInGrams) { super(weightInGrams); } public String getOrigin() { return "Japan"; } } /** * A specific variety of apple. * @author Adam J. Conover */ class Gala extends Apple implements Origin { public Gala(float weightInGrams) { super(weightInGrams); } public String getOrigin() { return "New Zealand"; } } /** * A specific variety of apple. * @author Adam J. Conover */ class HoneyCrisp extends Apple implements Origin { public HoneyCrisp(float weightInGrams) { super(weightInGrams); } public String getOrigin() { return "Minnesota"; } } /** * Though there are specific varieties of Oranges too, for this example we'll * treat an Orange as it own concrete class. * * @author Adam J. Conover */ class Orange extends Fruit { // The average in normal seeded oranges. private static final float CALORIES_PER_GRAM = .37f; public Orange(float weightInGrams) { super(weightInGrams); super.calories = CALORIES_PER_GRAM; } public String getHabitat() { return "Tropical"; } } /** * A trademarked variety of seedless orange. * @author Adam J. Conover */ class Sunkist extends Orange implements Origin { // According the Sunkist site: private static final float AVG_WEIGHT = 154; private static final float CALORIES_PER_GRAM = .519f; public Sunkist() { super(AVG_WEIGHT); super.calories = CALORIES_PER_GRAM; } public String getOrigin() { return "California"; } }