Java Generics Flashcards
Collection extends Number> is a GET-ONLY subtype of Collection where T is subtype of Number
REMOVE considered as GET
When you see
void foo(Collection extends Number>) { }
It says this function accepts collections of Integer|Double… to READ/GET (include remove) but not to add new element (How is this enforced by JVM?)
The Java Generics Get (? extend from T) and Put (? super of T) Principle
Get|Read via casting (concrete-type pointer)
Put|Write via void* (opaque pointer)
List extends T> e.g. List extends Number>
List super T> e.g List super Number>
T can only be bound to 1 specific type at a time, which is unknown to code inside generics.
List extends Number> means this list holds object of Number or subtype (Float, Integer…) It is safe to read all elements as Number, but it is not safe to put elements Integer or Float into it, because it could be List when you put Float into it.
List super Number> means the list holds object of Number or Object. It is safe to write Number or its subtypes to list, because the list can only be List or List which is safe to read Number|Float as Object or Number
void foo(List super Number> list);
what can we do with list inside foo?
TLDR: we can only write Integer or Float element into list because the list can only be List or List in either case it is to safe to read Float or Integer as Number or Object
void foo(List list);
what can we do with list inside foo?
TLDR: we can only read elements as Number because the list can be List or List (and inside foo() we don’t know which)
wildcard type does not guarantee immutability
wildcard is a compile time enforcement
[*] Covariant vs Invariant
Array of Box Types is Covariant, in that
S extends T then S[] extends T[]
Integer[] and Number[] are covariant
int[] is primitive type array, does not apply
Collection/List is invariant in that
S extends T but List does NOT extend List
Wildcard introduces Covariant to Collection/List
S extends T then List extend List extend T>
GET/PUT principal applies to Covariant types but violation of the principal is detected at different times (compile time vs run time)
List/Collection Covariant:
Get/PUT violation is detected at COMPILE time
Array Covariant:
GET/PUT violation is detected at RUN time (ArrayStoreException)
What is Covariance? (Origin of Array Covariant)
TLDR:
Covariance is the “is-a” relationship in inheritance tree.
We know that “Integer is-a Object”
Java, before generics, also defined that
Integer[] is-a Object[]
This allows void foo(Object[] a) to be called with foo(new Integer[3])
Unbounded Wildcard List> vs Bounded wildcard List extends T> or List super T> vs Bounded Type List
Unbounded wildcard: operations that does not depend on type (such as list.size())
Bounded wildcard : Put or Get but not both
Bounded Type: Put and Get
What is wrong with this (signage)
public int compareTo(Integer that) { // bad implementation -- don't do it this way! return this.value - that.value; }
this code may give the wrong answer when there is overflow. For instance, when
comparing a large negative value to a large positive value, the difference may be more
than the largest value that can be stored in an integer, Integer.MAX_VALUE
Type-Erasure (C++ Code specialization vs Java Code sharing)
C++ template uses Code Specialization (1 class generated for each concrete type used with template) Java generics uses Code sharing (1 class generated for ALL concrete types used with the template)
C++
template
class CList {
}
Java class JList { T t = new T(); // this is not possible since there is no "Type information" at run time. (Type-erasure) }
CList and CList are two different classes in C++
JList and JList are same class in Java. To do this java adopt type-erasure to remove all type information inside JList implementation. (I.e. you cannot instantiate objects of T inside JList)
Therefore, In java, Generics and Collection are tightly coupled where generics are usually used with collections where collection operation (len, size, iterate) does not require type info.
If type info is needed, then use Bounded Type extends Number> then you can reference elements as Number.
Types of outter class is visible to non-static inner class. (static nested class are like namespace, thus its type is separated from outter class types)
If the outer class has type parameters and the inner class is not static, then type parameters of the outer class are visible within the inner class.
ERASURE
what is it?
(Remember type bound is only done through extends not through “super” and there is no “bounding” done for > )
Erasure is process of enforcing type constraints only at compile time and discarding the element type information at runtime.
Drop all type parameters from parameterized types, and replace any type variable with its bound, or with Object if it has no bound, or with the interfaces if it has multiple bounds
Multiple bounds: A type T can have multiple bounds
List \ extends C1 & C2 & IF1 & IF2>
Thus the list element must be a subtype of C1&C2 and implements IF1 and IF2.
(C1 &C2 indicates multiple inheritance, BAD DESIGN!)
Java requires Class type precedes interface type
In Multiple bounds, usually 1 class and multiple interfaces, compiler erased the left most bound (class bound), and keep the remaining (interface bounds)
So compiler will erase Number and keep comparable.
This the generated class is Comparable max( Comparable x,...)
Signatures for methods should be as general as possible to maximize utility. If you can
replace a type parameter with a wildcard then you should do so.
We can improve the Signature of max by replacing: T max(Collection collection) with: T max(Collection \< ? extends T> coll)
Why is System::arraycopy() a native method?
In native mode, it allows using pointers to fast access to consecutive objects in continuous memory block (e.g. memcpy()) and other optimizations.
I.e. do a block memcpy() instead of object-wise copy