Java

Because Java employes type erasure, it is not possible, nor would it be useful, to create new, generic types at runtime. Take the following program:

  1. import java.lang.Class;
  2. import java.util.ArrayList;
  3. import java.lang.reflect.Constructor;
  4. class Main {
  5. public static void printLen(ArrayList<?> list) {
  6. System.out.println(list.size());
  7. }
  8. public static void main(String[] args) throws Exception {
  9. // We can get the Class based on a string value -- a useful feature for
  10. // some meta programming.
  11. Class<?> intClass = Class.forName("java.lang.Integer");
  12. // Get the constructor for instantiating an ArrayList.
  13. Constructor<ArrayList> listCtor = ArrayList.class.getDeclaredConstructor();
  14. // But there is no way to instantiate ArrayList using the intClass!
  15. // Instead all we can do is create the ArrayList the way it would look
  16. // at runtime anyway.
  17. ArrayList ints = listCtor.newInstance();
  18. // Add some integers to the list.
  19. ints.add(1);
  20. ints.add(2);
  21. ints.add(3);
  22. // And because there is no type safety for lists created at runtime,
  23. // and we used reflection to mimic that here, there's no compile-time
  24. // type safety either!
  25. ints.add("Hello");
  26. // That said, we *can* assert some compile-time type safety back into
  27. // the mix by randomly declaring "strs" to be an ArrayList<String>.
  28. //
  29. // But remember, we did *nothing* to ensure the underlying storage of
  30. // strs is bound to the String class. Again, this is purely a compile-
  31. // time conveience feature.
  32. ArrayList<String> strs = listCtor.newInstance();
  33. strs.add("Hello");
  34. strs.add("world");
  35. // By asserting that strs is "ArrayList<String>", the following line
  36. // would cause a compile error as expected.
  37. // strs.add(1);
  38. printLen(ints);
  39. printLen(strs);
  40. }
  41. }

The code comments in the above program demonstrate that Java does not allow runtime instantiation from generic types. Which makes sense, as generics are strictly a compile-time convenience feature in Java.

To run the above program, please follow these instructions:

  1. Launch the container:

    1. docker run -it --rm go-generics-the-hard-way
  2. Compile the above program:

    1. javac -g ./05-internals/03-runtime-instantiation/java/main.java
  3. Run the program:

    1. java -classpath ./05-internals/03-runtime-instantiation/java Main
    1. 4
    2. 2
  4. Type exit to stop and remove the container.

It bears saying once more — generics in Java are purely a compile-time, convenience feature. What about .NET and Go?


Next: .NET