Incidentally if you do what they're proposing for PHP in Java (where you define a non-generic subclass of a generic type), the actual generic type parameters actually are in the bytecode, and depending on the static type you use to reference it, may or may not be enforced...

   public class StringList extends java.util.ArrayList<String> {
       public static void main(String[] args) throws Exception {
           StringList asStringList = new StringList();
           java.util.ArrayList<Integer> asArrayList = (java.util.ArrayList<Integer>)(Object)asStringList;
           System.out.println("It knows it's an ArrayList<String>: " + java.util.Arrays.toString(((java.lang.reflect.ParameterizedType)asArrayList.getClass().getGenericSuperclass()).getActualTypeArguments()));
           System.out.println("But you can save and store Integers in it:");
           asArrayList.add(42);
           System.out.println(asArrayList.get(0));
           System.out.println(asArrayList.get(0).getClass());
           System.out.println("Unless it's static type is StringArrayList:");
           System.out.println(asStringList.get(0));
       }
   }
That prints out:

   It knows it's an ArrayList<String>: [class java.lang.String]
   But you can save and store Integers in it:
   42
   class java.lang.Integer
   Unless it's static type is StringArrayList:
   Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
    at StringList.main(StringList.java:11)