// Generics in java // tradeoff with C++. Runtime overhead, but with some static type checking // of generic class/functions, though not very well done. // Generic types are only checked at compile time, not at runtime. // At runtime, all generic type info is lost. //If you create in Java: import java.util.ArrayList; import java.util.HashMap; class generalclass> { A x; B y; A[] ar; void f() // generic code type checked { //int z = x+1; // won't compile (will in c++) y = (B)x; // will this compile? IT WILL, with a warning (!) //Integer z = (Integer)y+1; // this will also compile with warning // no generic array creation in java //A[] array = new A[10]; // won't compile "generic array creation error" ar = (A[])new Object[10]; // workaround, gets compiler warning. B[] arr = (B[]) new Comparable[10]; // but new Object[10] still compiles // Can we create an array of hashmaps? (java.util.HashMap) //HashMap[] array2 = new HashMap[4]; // Won't compile: this is also "generic array creation" even thout // no generic type variable occurs (all types known!) ar[0] = (A)"abc123"; /// LOOK MA, BOTH LINES COMPILED! ar[1] = (A)(new Double(0.25)); arr[0] = (B)ar[0]; // A is not even Comparable, but casts to B? ArrayList al = new ArrayList(); //generic "arraylist" creation OK! ArrayList am = (ArrayList)new ArrayList(); //?? compiled! // ****type casting is not checked at all between generics. ar = (A[]) new String[10]; /// YIKES MA! THIS COMPILED TOO! // what if there's an instance // var n = new generalclass(); // then n.ar should be a Double[] array no? how can a Double[] // array be assigned to a String[]? //*********** What's causing all this? // It all comes down to the fact that arrays are covariant in Java, // but they shouldn't be. That is, String[] is considered a subtype // of Object[]: //String[] os = new Object[10]; does not compile (not "contravariant") Object[] oa = new String[10]; // compiles - arrays are "covariant" oa[0] = "abc"; oa[1] = new Double(3.5); // this compiles too, obviously not type safe. String[] sa = (String[]) new Object[10]; // this also compiles (yikes). // Arrays are made covariant because pre-generics Java needed it. // But generic structures should observe the rules of co/contravariance. // They often can't be either (invariant). //generalclass g = // (generalclass)new generalclass(); // won't compile even with cast, (not just warning but error), because // both classes are actually same as generalclass. // Generic array creation: new T[] is just new Object[], and because // java DOES allow covariant arrays, the T[] can be cast to anything, // thus violating the invariance of the type variable. But creating // a new T[] is still possible with type casting, resulting only in // a compiler warning. So in the end, the restriction of not allowing // generic array creation is a FUTILE attempt at correcting the mistake // of allowing for covariant arrays in the first place. // but ArrayList n= new ArrayList() does not compile, // so it's perfectly fine to use generic "ArrayLists" instead of // generic Arrays. }//function f // final piece of headache: //public static A z; // a static variable of generic type won't compile }// a java generic class and it's problems. /* Java will create internally the following class: class generalclass { Object x; Comparable y; } "Comparable" is a non-generic version of Comparable that contains a function int compareTo(Object x) Java will type-check your generic class at compile time, but it is this class that's used at RUNTIME. This means that, at runtime, there's no difference between generalclass and generalclass: they're all the same. This is called **Type Erasure**. The compiler warning in y = (B)x is issued because the compiler cannot guarantee that the cast will be valid at runtime. Normally Object x; Comparable y; x = y; // will compile without errors. y = (Comparable)x; // should compile, but may result in runtime error. **But if x and y were instead instances of subclasses of Object and Comparable, then the compiler will not know that the casting is invalid. //A[] array = new A[10]; // won't compile "generic array creation error" A[] array = (A[])new Object[10]; // workaround, gets compiler warning. What explains this? Object[] Ar = new String[Integer]; // this is allowed, even though: Ar[1] = 2; // this compiles but gives runtime error ArrayList al = new ArrayList(); // will not compile Arrays are "covariant" but generic structures are "invariant" If we allowe A[] array to be created directly, then later do Object n = array, we would have violated the invariance of generic variable A. The (static) type of Ar is Object[]. We don't know what the type of A will be at runtime (from the perspective of the compiler), it could be something incompatible with String, and this is not checked at compile time. So now in A[] X = (A[]) Ar; At compile time, we don't know what type A will be instantiated with at compile time, so we don't know if the cast is between String[] and int[], the compiler can't catch this. but: ArrayList al = new ArrayList(); // generic "arraylist" creation OK! Because ArrayList ao = new ArrayList(); won't compile! This means that the static and dynamic types of ao will be the same! Finally, static A z; // not allowed by compiler. Of course! at compile time generalclass and generalclass are different, but at runtime they're all the same! That's why the type variable A itself is not considered static. These classes should each have its own static variable z, one of type String and the other one of type Boolean. But the actual variable at runtime, if it's allowed to be created, will be of type Object and be shared by the two classes. */