Java Tech: Generics and You Blog

Version 2

    {cs.r.title}



              
                     

    Contents
    Take the Test
    Review a nd Compare
    Conclusion
    Resources
    Answers to Previous Homework

    How much do you know about generics? Based on your amount of generics knowledge, are you comfortable with having to maintain another developer's generified code, should your project manager tell you to do so? Perhaps you have not taken the time to determine how much you know about generics and how much you still have to learn. If you would like to assess your generics I.Q., you might find this article a helpful test of your generics knowledge.

    Note: This article bases its content on a very useful and extensive generics FAQ that I discovered a couple of months ago. After you finish this article, do yourself a favor by checking out the FAQ, listed in the Resourcessection at the end of the article.

    Take the Test

    This section presents a test on several generics concepts. The test's 20 questions are a mixture of fill in the blank, true/false, multiple choice, and long answer. Take all the time you need to complete this test, but resist the urge to peek at the answers (which I present in the next section) until you finish. The test begins now.

    1. Generics identifies language features for defining and using ________________ and ________________.

    2. What is a parameterized type?

    3. How does generics promote type safety?

    4. Which of the following reference types cannot be generic?

      1. Anonymous inner class
      2. Interface
      3. Inner class
      4. All of the above
    5. True or false: Set<Object> is the supertype of Set<String>.

    6. What is a type parameter?

    7. A ________________ describes a family of types and is used as a type parameter.

    8. How is a concrete parameterized type different from a non-concrete parameterized type?

    9. True or false: parameterized types have type parameters.

    10. Which syntax would you use to express a wildcard with a lower bound of some type?

      1. ?
      2. ? extends type
      3. ? super type
      4. None of the above
    11. Identify those types that cannot be used as type arguments.

    12. Why can you not derive (directly or indirectly) generic classes from Throwable?

    13. What is type erasure?

    14. Identify the tasks performed by type erasure.

    15. True or false: The parameterized typesList<Date> and List<?> share the same runtime type.

    16. The opposite of type erasure is known as ________________.

    17. Which overloaded method is called by the following program?

       
      // Overload.java import java.util.Date; public class Overload { public static void someOverloadedMethod (Object o) { System.out.println ("call to someOverloadedMethod(Object o)"); } public static void someOverloadedMethod (Date d) { System.out.println ("call to someOverloadedMethod(Date d)"); } public static <T> void methodCaller (T t) { someOverloadedMethod (t); } public static void main (String [] args) { methodCaller (new Date ()); } }
      
    18. What is an "unchecked" warning message?

    19. When the compiler reports an unchecked or unsafe operation, it also tells you to recompile with the ________________ option to obtain details.

    20. True or false: the code fragment System.out.println (o instanceof Set<String>); will compile.

    Review and Compare

    Now that the test is over, it's time to find out how well you understand generics. This section repeats the questions stated in the previous section, but it also presents the answers (in red) to those questions. Review those answers and compare them to your responses. Give yourself one mark for each correctly answered question. If you believe you got a question partially right, give yourself half of one mark. Add up the marks and multiply by 5 to receive your test score.

    1. Generics identifies language features for defining and usinggeneric types and generic methods.

    2. What is a parameterized type?

      A parameterized type is an instance of a generic type. Example: HashMap<K,V> is a generic type and HashMap<String,Double> is an instance of that type--a parameterized type.

    3. How does generics promote type safety?

      Prior to J2SE 5, Java's Collections framework did not provide for homogeneous collections--collections whose elements all share the same type. Collections held Object references, raising the possibility of heterogeneous collections--collections with elements of different types. Collection APIs revealed this heterogeneous bent by accepting arbitrary elements for insertions, and by returning Object references when retrieving elements from collections.

      The problem with heterogeneous collections: lack of type safety. Because a retrieval operation requires a cast operation, to downcast from Object to the returned object's type, before assigning the returned object to a variable of that type, there is a potential for aClassCastException, should an object not match or subtype that type. The following code fragment illustrates this problem:

       
      
      List integers = new ArrayList (); integers.add (new Integer (25)); integers.add (new Integer (-367)); integers.add (BigInteger.ONE); Iterator it = integers.iterator (); while (it.hasNext ()) { Integer i = (Integer) it.next (); // Do something with i }
      

      The code fragment is problematic because of the (Integer) cast. That cast signifies our assumption that integers is a homogeneous collection of Integer objects. But that is not the case: there is nothing to prevent us from adding BigIntegers (or other kinds of objects) to integers. When retrieving the BigInteger from the collection, that cast results in a thrown ClassCastException: we cannot cast fromBigInteger to Integer.

      To avoid ClassCastExceptions, we need to prevent non-Integer objects from being added to the List. Generics lets us accomplish that task. Consider the following code fragment:

       
      
      List<Integer> integers = new ArrayList<Integer> (); integers.add (new Integer (25)); integers.add (new Integer (-367)); integers.add (BigInteger.ONE); Iterator<Integer> it = integers.iterator (); while (it.hasNext ()) { Integer i = it.next (); // Do something with i }
      

      Unlike the previous code fragment, which uses the raw List type to create an object representing a heterogeneous List, this code fragment uses generics to create a parameterizedList<Integer> type. That type'sintegers object represents a homogeneousList of Integers. The compiler, which has access to this type information, displays an error message when encountering integers.add (BigInteger.ONE);:List<Integer> has no method for adding aBigInteger to a List ofIntegers.

      Because integers has theList<Integer> type, its iterator()method returns an object of Iterator<Integer>type. This object's next() method will only returnInteger objects; a cast is not required (which reduces source code clutter) and a ClassCastException cannot occur. By providing static type information, so that the compiler can enforce a homogeneous List ofIntegers, generics has made this code type-safe.

    4. Which of the following reference types cannot be generic?

      1. Anonymous inner class
      2. Interface
      3. Inner class
      4. All of the above
    5. True or false: Set<Object> is the supertype of Set<String>.

      False. There is no type relationship between different instances of the same generic type for different concrete type arguments.

    6. What is a type parameter?

      A type parameter is a stand-in for a type argument. For example, the E in public class TreeSet<E> is a type parameter. It will be replaced with a type argument when creating an instance of a generic type. Example: new TreeSet<String>.

    7. A wildcard describes a family of types and is used as a type parameter.

    8. How is a concrete parameterized type different from a non-concrete parameterized type?

      A concrete parameterized type cannot have wildcards as its type arguments. Wildcards are permitted for non-concrete parameterized types.

    9. True or false: parameterized types have type parameters.

      False. Parameterized types, which are instances of generic types, have type arguments.

    10. Which syntax would you use to express a wildcard with a lower bound of some type?

      1. ?
      2. ? extends type
      3. ? supertype
      4. None of the above
    11. Identify those types that cannot be used as type arguments.

      All primitive types, such asint, char, and double, cannot be used as type arguments. In contrast, all references types, including parameterized types (such asArrayList<Set<String>>), can be used as type arguments.

    12. Why can you not derive (directly or indirectly) generic classes from Throwable?

      Generics-based exception and error classes are not allowed because the exception-handling mechanism is JVM-based and the JVM knows nothing about generics.

    13. What is type erasure?

      Type erasure is a compiler activity where all instances of a generic type or a generic method are mapped to the unique bytecode representation of the generic type or generic method.

    14. Identify the tasks performed by type erasure.

      Type erasure 1) elides type parameters (upon encountering a generic type definition or a generic method definition, the compiler removes all type parameters and replaces them with their leftmost bound or the Object type, if there is no bound), and 2) elides type arguments (upon encountering a parameterized type, the compiler removes all type arguments--List<Integer> is translated toList, for example).

    15. True or false: the parameterized typesList<Date> and List<?> share the same runtime type.

      True. All parameterized versions ofList (including the List raw type) are represented by the same Class object, which serves as the runtime type.

    16. The opposite of type erasure is known as reification.

    17. Which overloaded method is called by the following program?

       
      // Overload.java import java.util.Date; public class Overload { public static void someOverloadedMethod (Object o) { System.out.println ("call to someOverloadedMethod(Object o)"); } public static void someOverloadedMethod (Date d) { System.out.println ("call to someOverloadedMethod(Date d)"); } public static <T> void methodCaller (T t) { someOverloadedMethod (t); } public static void main (String [] args) { methodCaller (new Date ()); } }
      

      Although you might think otherwise, the program above calls someOverloadedMethod(Object o). This method, instead of someOverloadedMethod(Date d), is called because overload resolution happens at compile time, when the generic method is translated to its unique bytecode representation, and type erasure (which takes care of that mapping) causes type parameters to be replaced by their leftmost bound orObject (if there is no bound). After type erasure, we are left with the following non-generic method:

       
      
      public static void methodCaller (Object t) { someOverloadedMethod (t); }
      
    18. What is an "unchecked" warning message?

      Occasionally, you may encounter a compiler warning message stating that an operation is unchecked. For example, you may be told about an unchecked call to anadd(E) method. This "unchecked" warning message is due to the compiler and runtime system not having sufficient type information to ensure type safety.

      The use of raw types (especially in legacy code) serves as the most likely culprit of "unchecked" warning messages. Because raw types don't provide enough type information, it is impossible for the compiler to perform all of its needed type checks. Consider the code fragment below:

       
      
      Map colors = new HashMap (); colors.put ("red", Color.red);
      

      The code fragment concerns itself with mapping AWT-based Color objects to descriptive names, which are represented by String objects. When you compile this code, the compiler reveals the following warning message:

       
      
      warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.Map
      

      Map's put()method invocation causes a problem for the compiler. It does not know if it's safe to put an entry, consisting of aString-based key and a Color-based value, into the Map. The raw Map type's lack of specific type information for its entries makes this call unsafe, and so the compiler reports the warning. Of course, changingcolors' declaration to Map<String,Color> colors = new HashMap<String,Color> (); provides this information; the warning is no longer necessary.

    19. When the compiler reports an unchecked or unsafe operation, it also tells you to recompile with the -Xlint:unchecked option to obtain details.

    20. True or false: the System.out.println (o instanceof Set<String>); code fragment will compile.

      False. The code fragment will not compile because Set<String> does not have an exact runtime type representation. Following type erasure, the runtime type becomes the raw type Set. Becauseinstanceof can only check against Set, and not Set<String>, confusion results. To prevent this confusion, the compiler disallows the code fragment.

    Conclusion

    After obtaining your test score, you might be feeling depressed or elated. If you received a low score, this does not mean you are a loser when it comes to generics. Instead, the score means you have lots of learning to do; this is important if you might be called upon to maintain another developer's generified code. On the other hand, receiving a high score does not mean you have little else to learn about generics. All tests present samples of subject material, and this test is no different. If you are deficient in a category that the test has not covered, that deficiency will not be revealed by the test. Regardless of your score, I hope that you have found this test to be enlightening, and I hope that it enhances your understanding of generics.

    Resources

    Answers to Previous Homework

    The previous Java Tech article presented you with some challenging homework on BlueJ. Let's revisit that homework and investigate solutions.

    1. For space reasons, I was unable to dig into BlueJ's support for applets. Therefore, your new homework is to investigate BlueJ's applet support and answer the following questions: how do you create an applet in BlueJ? And can you set breakpoints in the applet?

      Create an applet first by clicking the project toolbar's New Class... button, and next by selecting the resulting Create New Class dialog box's Applet radio button. Although you can set breakpoints in the applet, they will have no effect during the applet's execution in a web browser or in theappletviewer--those tools have their own virtual machines, and those virtual machines don't recognize breakpoints.

      
    http://today.java.net/im/a.gif