OOP Class Notes for 10/10/13
Java Generics
- If we wanted to implement two singly linked lists, one of doubles and one of strings. What should we do?
- In approach 1, we can use
Objectto represent the members of each list because all Java classes inherit fromObject - However, using
Objectcreates the following problems:- Primitive types must be dynamically converted to their respective boxed types (i.e.
doubletojava.lang.Double, etc.) - There are too many casts, leaving much room for error and reducing readability
- Elements of the list must be dynamically cast to desired types (i.e.
Double) - There is no static assurance for type uniformity across members of the list
- There is no static assurance that a method acting on lists of a given type is actually called on a list of that type; we only know that said method acts on a list of some type
- Primitive types must be dynamically converted to their respective boxed types (i.e.
- In approach 1, we can use
- We can improve this code by implementing the list using Java generics
- Java Generics
- Add type parameters to classes
- Syntax for defining type parameter
Tof generic typeList:public class List<T> { } - To create lists, a concretely defined type argument must be supplied to the constructor (e.g.
new List<String>( /* */ )) - Methods acting on lists of a specific type can now
specify
List<T>as a parameter. For example, a method that works on a list ofStringobjects can specifyList<String>as a parameter - Now, you have static safety in your lists; the compiler will detect errors generated when an element of a list does not match the predefined type of the list
- Type erasure -- removes generic type information from source code, adds casts as needed, and produces byte code
- Essentially, the <s and >s go away and the compiler generates exactly the same naive code we wrote in approach 1
- Why is this the way the compiler works?
- Because it does not require the JVM to be changed (generics were only introduced with version 1.5 of the Java language)
- Type erasure still allows the compiler to catch static type safety errors
- No generic arrays or instantiations using the
newkeyword - Can't handle primitive types, which require wrapper classes
- Java does have auto-boxing and auto-unboxing to make conversions from primitive types to boxed types and back again, but this has an overhead cost
C++ Templates
- Templates are the C++ version of Java Generics, except that they are more flexible
- Templates can be made for classes and functions, and said templates allow classes and functions to intake many different types
- You can implement
newkeyword instantiations, generic arrays and have static fields that are generic
- Class Templates
- Class parameters can be generically defined to increase flexibility of a class
- Syntax:
template<typename T /* further generic parameters */ > class List { ... } - Using this approach, data structures can be created and used to handle many different types without declaring separate classes for each
- Declaring and Defining Templates
- Class templates must be declared in the header file
- The compiler instantiates the template, replacing all instances of
Twith the actual type
- The compiler instantiates the template, replacing all instances of
- Class templates must also be defined in the header file
- Class templates must be declared in the header file
- Template Specialization
- Specialized versions of class templates can be created for specific types
- Syntax:
template<> class Name<Types> { ... } - For the specified types, the compiler will use the specialized templates
- Defined in .cc (implementation) files because they don't need to be instantiated by the compiler
- For array templates in our project (the only time we can use templates), we cannot define the
__class()method in the header file because the dynamic type of the returned class changes depending on the given array type
- Templates allow us, at a high level, to write code that abstracts over a type so we can write the code only once, giving us type safety in C++