/* SuperTEst.java * Created on February 21, 2006, 4:53 PM */ package Generics; import java.util.Vector; /** * Important note: Generic types are checked at COMPILE TIME not RUN TIME! This * is to enforce the strong/static typing inherent in Java. * * This set of examples uses the hierarchy of "Food" classes in {@link Food}. * I don't show how to create generified classes in this example, but instead show * how to properly use existing generified classes and how to create generified * methods which accept and return generified types. * * @author Adam J. Conover */ public class GenericVectors { /** * Main method. Serves as the entry point into our test application. * @param args */ public static void main(String[] args) { // Declare some objects of differnet types. Note: The ONLY reason the // types are declared as they are here is for the sake of example! Fuji f1 = new Fuji(335); // The variable is an exact type. Apple f2 = new Gala(300); // The variable is a super type. Orange f3 = new Orange(250); // The variable is an exact type. Orange f4 = new Sunkist(); // The variable is a super type. Apple f5 = new HoneyCrisp(350); // The variable is a super type. Fruit f6 = new Sunkist(); // The variable is an even more generic super type. // A Vector that will hold only apples Vector apppleBasket = new Vector(); apppleBasket.add(f1); // A Fuji "is an" Apple, so it's ok. apppleBasket.add(f2); // A Vector that will hold only Oranges Vector orangeBasket = new Vector(); orangeBasket.add(f3); orangeBasket.add(f4); // A Vector that will hold any type of Fruit Vector fruitBasket = new Vector(); // Since all of the above are of type "Fruit" they can all go in the basket. fruitBasket.addAll(apppleBasket); // add the Vector of Apples since Apples are Fruit fruitBasket.addAll(orangeBasket); // add the Vector of Oranges since Oranges are Fruit fruitBasket.add(f5); fruitBasket.add(f6); // Total the amount of calories in the entire basket. float caloriesInBasket = 0; for (Fruit f : fruitBasket) { caloriesInBasket += f.getTotalCalories(); } System.out.println("Calories in basket: " + caloriesInBasket); // Create a new basket (from the old one) that is even more generic. Vector foodBasket = new Vector(fruitBasket); // Since we can put fruit in a food basket, this call is perfectly legal. putFirst(foodBasket, new Fuji(327)); // Since we know that the basket has Food in it we can do this: Food foodItem = getFirst(foodBasket); // Apples and Oranges have "Fruit" in common. Since Fruit implements // Comparable, this call will work with or without wildcard caputure. // Try replacing the "? super T" portion of getBiggest() with just "T" // and see what happens. This will still compile. The next line will not. Fruit a = getBiggest(f5, f3); // And who said you couldn't comapre apples and oranges? // However, "Wildcard capture" is nexessary to make this work, since // Apple is a subtype of something that is comparable to Fruit. Both // "Fuji" and "Gala" are of type "Apple". Apple b = getBiggest(new Gala(302), new Fuji(367)); // This will not work (Vector does not extend Vector) // Vector headAndTail = getHeadAndTail(basket); // However this does work: Vector headAndTail1 = getHeadAndTail(fruitBasket); // Normally, you would probably just want to do this: Vector headAndTail2 = getHeadAndTail(fruitBasket); } //////////////////////////////////////////////////////////////////////////// // EXAMPLE METHODS BELOW THIS POINT //////////////////////////////////////////////////////////////////////////// /** * "? extends Food" states: "I don't know what type of vector I'll be dealing * with, but I know I can legally take Food from it." * * @param basket The Vector of food items. * @return the first item in the vector. */ static Food getFirst(Vector basket) { System.out.println("IN: getFirst(Vector basket))"); // Can't to this (why?): // basket.add(new Fuji(333)); return basket.firstElement(); } /** * An even more generic version of the above method. "Type inference" is used * by the compiler to make sure that what is returned is of the same type as * what is actually contained in the Vector. * * @param basket A basket (vector) that food items can be put into. * @return the first item in the vector, which will be known to be of type T */ static T getFirst(Vector basket) { System.out.println("IN: getFirst(Vector basket)"); return basket.firstElement(); } /** * "? super Food" states: "I don't know what type of vector I'll be dealing * with, but I know I can legally put Food into it." * * @param basket A basket (vector) that food items can be put into. * @param f An instance of an apple (which extends food). */ static void putFirst(Vector basket, Apple f) { System.out.println("IN: putFirst(Vector basket, Apple f)"); // Can't do this (why?): // Food food = basket.firstElement(); basket.add(0, f); } /** * An even more generic version of the above method. Type inference is used * by the compiler to make sure that the second parameter is actually something * that can be placed into the vector in the first parameter. * * @param basket A basket (vector) that items of type T can be put into. * @param f An instance of type T which can be put into the basket (vector). */ static void putFirst(Vector basket, T f) { System.out.println("IN: putFirst(Vector basket, T f)"); basket.add(0, f); } /** * This is a more complicated example. It says, "Take two things which are * comparable, and specifically comparable to each other, but one may be a * super-type of the other (or share a super type). * * @param The generic type of object being compared. * @param obj1 The first object in the comparison. * @param obj2 The second object in the comparison. * @return The largest object, as a result of the comparison. */ static > T getBiggest(T obj1, T obj2) { if (obj1.compareTo(obj2) >= 0) { return obj1; } else { return obj2; } } /** * Though things can get a bit more complicated in theory, this method is about * as complex as things actually get in practice. This methods will get the head * and tail items of a vector of items which are comparable to each other and * return a new Vector with the two items in ascending order. * * @param The generic type of object contained in the Vector. * @param vect The vector of generic types. * @return The head and tail items of the original vector in a new vector, * in ascending order. */ static > Vector getHeadAndTail(Vector vect) { T headItem = vect.firstElement(); T tailItem = vect.lastElement(); Vector rtnVector = new Vector(); if (headItem.compareTo(tailItem) <= 0) { rtnVector.add(headItem); rtnVector.add(tailItem); } else { rtnVector.add(tailItem); rtnVector.add(headItem); } return rtnVector; } }