CS61B Lecture #25: Java Generics
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 1
The Old Days
Copyright By PowCoder代写 加微信 powcoder
• Java library types such as List didn’t used to be parameterized. All Lists were lists of Objects.
• So you’d write things like this:
for (int i = 0; i < L.size(); i += 1)
{ String s = (String) L.get(i); ... }
• That is, must explicitly cast result of L.get(i) to let the compiler
know what it is.
• Also, when calling L.add(x), was no check that you put only Strings into it.
• So, starting with 1.5, the designers tried to alleviate these per- ceived problems by introducing parameterized types, like List
• Unfortunately, it is not as simple as one might think.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 2
Basic Parameterization
• From the definitions of ArrayList and Map in java.util:
public class ArrayList
public boolean add(Item x) { … }
public interface Map
Value get(Key x);
• First (blue) occurrences of Item, Key, and Value introduce formal type parameters, whose “values” (which are reference types) get substituted for all the other occurrences of Item, Key, or Value when ArrayList or Map is “called” (as in ArrayList
• Other occurrences of Item, Key, and Value are uses of the formal types, just like uses of a formal parameter in the body of a function.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 3
Type Instantiation
• Instantiating a generic type is analogous to calling a function.
• Consider again
public class ArrayList
public boolean add(Item x) { … }
• When we write ArrayList
somewhat like
public String ArrayList implements List
public boolean add(String x) { … }
• And then, likewise, List
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 4
Parameters on Methods
• Functions (methods) may also be parameterized by type. Example of use from java.util.Collections:
/** A read-only list containing just ITEM. */
static
static
The compiler figures out T in the expression singleton(x) by look- ing at the type of x. This is a simple example of type inference.
• In the call
List
the parameters obviously don’t suffice, but the compiler deduces the parameter T from context: it must be assignable to String.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 5
• Consider the definition of something that counts the number of times something occurs in a collection of items. Could write this as
/** Number of items in C that are equal to X. */
static
for(Ty:c) {
if (x.equals(y))
return n; }
• But we don’t really care what T is; we don’t need to declare anything of type T in the body, because we could write instead
for (Object y : c) {
• Wildcard type parameters say that you don’t care what a type pa- rameter is (i.e., it’s any subtype of Object):
static int frequency(Collection> c, Object x) {…}
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 6
Subtyping (I)
• What are the relationships between the types
List
List
String S = LS.get(0);
// Legal, since A is an Object
// OOPS! A.get(0) is NOT a String, // but spec of List
Subtyping (II)
• Consider this fragment:
List
• So, having List
• So in general for T1
• But what about T1 and T2?
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 8
Subtyping (III)
• Now consider
ArrayList
List
– The object’s dynamic type is ArrayList
– Therefore, the methods expected for LS must be a subset of
those for ALS.
– And since the type parameters are the same, the signatures of
those methods will be the same.
– Therefore, all the legal calls on methods of LS (according to the
compiler) will be valid for the actual object pointed to by LS. • In general, T1
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 9
A Java Inconsistency: Arrays
• The Java language design is not entirely consistent when it comes to subtyping.
• For the same reason that ArrayList
• And yet, Java does make String[] ≼ Object[].
• And, just as explained above, one gets into trouble with
String[] AS = new String[3]; Object[] AObj = AS;
AObj[0] = new int[] { 1, 2 }; // Bad
• So in Java, the Bad line causes an ArrayStoreException—a (dy- namic) runtime error instead of a (static) compile-time error.
• Why do it this way? Basically, because otherwise there’d be no way to implement, e.g., ArrayList.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 10
Type Bounds (I)
• Sometimes, your program needs to ensure that a particular type pa- rameter is replaced only by a subtype (or supertype) of a particular type (sort of like specifying the “type of a type.”).
• For example,
class NumericSet
T min() { … }
Requires that all type parameters to NumbericSet must be subtypes of Number (the “type bound”). T can either extend or implement the bound, as appropriate.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 11
Type Bounds (II)
• Another example:
/** Set all elements of L to X. */
static
means thatLcan be aListfor anyQas long asTis a subtype of
(extends or implements) Q.
• Why didn’t the library designers just define this as
/** Set all elements of L to X. */
static
Last modified: Fri Oct 25 14:33:03 2019
CS61B: Lecture #25 12
Type Bounds (II)
• Another example:
/** Set all elements of L to X. */
static
means thatLcan be aListfor anyQas long asTis a subtype of
(extends or implements) Q.
• Why didn’t the library designers just define this as
/** Set all elements of L to X. */
static
• Consider
static void blankIt(List
This would be illegal if L were forced to be a List
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 13
Type Bounds (III)
• And one more:
/** Search sorted list L for KEY, returning either its position (if * present), or k-1, where k is where KEY should be inserted. */
static
• Here, the items of L have to have a type that is comparable to T’s or to some supertype of T.
• Does L have to be able to contain the value key?
• Why does this make sense?
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 14
Type Bounds (III)
• And one more:
/** Search sorted list L for KEY, returning either its position (if * present), or k-1, where k is where KEY should be inserted. */
static
• Here, the items of L have to have a type that is comparable to T’s or to some supertype of T.
• Does L have to be able to contain the value key?
• Why does this make sense?
• As long as the items in L can be compared to key, it doesn’t really matter whether they might include key (not that this is often use- ful).
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 15
Dirty Secrets Behind the Scenes
• Java’s design for parameterized types was constrained by a desire for backward compatibility.
• Actually, when you write
class Foo
T mogrify(T y) { … } Java really gives you
class Foo { Object x;
Object mogrify(Object y) { … }
That is, it supplies the casts automatically, and also throws in some additional checks. If it can’t guarantee that all those casts will work, gives you a warning about “unsafe” constructs.
Foo
Integer r = q.mogrify(s);
Foo q = new Foo();
Integer r =
(Integer) q.mogrify((Integer) s);
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 16
Limitations
Because of Java’s design choices, there are some limitations to generic programming:
• Since all kinds of Foo or List are really the same,
– L instanceof List
– Inside, e.g., class Foo, you cannot write new T(), new T[], or x instanceof T.
• Primitive types are not allowed as type parameters.
– Can’t have ArrayList
– Fortunately, automatic boxing and unboxing makes this substitu- tion easy:
int sum(ArrayList
for(intx:L) { N+=x; }
return N; }
– Unfortunately, boxing and unboxing have significant costs.
Last modified: Fri Oct 25 14:33:03 2019 CS61B: Lecture #25 17
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com