Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't you create an instance of a generic type using "new" operator?

I found a lot of posts about how to overcome this limitation, but none about why this limitation exists (except this one, which just mentions it has to do with type erasure).

So why can't you create an instance of a generic type?

To clarify, my question is not how it can be done. I know it's possible in C#, so why not in Java? I'm curious about why the Java folks did not implement a similar mechanism? Why force Java developers to use awkward workarounds that have the potential to result in a runtime error? Are there any potential hazards from such a mechanism?

like image 904
traveh Avatar asked Jun 04 '15 14:06

traveh


1 Answers

The shortest answer is that generic type parameters do not exist at runtime.

Generics were retrofitted into the Java language in release 5. In order to maintain backward compatibility with the existing code base, they were implemented by erasure.

Generic type parameters exist in your source code at compile-time, but nearly all evidence of them is removed in the byte code during compilation. This implementation of generics was chosen because it maintained inter-operability between pre-generics code and Java 5+ generic code. Type safety with generics is largely, therefore, a compile-time only phenomenon. If your generic code compiles without error and without warnings, then you are assured that your code is type safe.

Because of erasure, however, there are (as of Java 5) two kinds of types:

  • Reifiable. For example String, Integer, etc. A reifiable type has the same type information at compile-time as it has at run-time.

  • Non-reifiable. For example List<String>, List<T>, and T. Non-reifiable types have less type information at run-time that at compile time. In fact, the run-time types of the above are List, List, and Object. During compilation, the generic type information is erased.

You cannot use the new operator with non-reifiable types because there is no type safe way at run-time for the JVM to generate an object of the correct type.

Source code:

T myObject = new T();

The above does not compile. At run-time, T has been erased.

A strategy for circumventing some problems with type erasure and Java generics is to use type tokens. This strategy is implemented in the following generic method that creates a new T object:

public <T> T newInstance(Class<T> cls) {
    T myObject = cls.newInstance();
    return myObject;
}

The generic method captures the type information from the Class object that is passed as a parameter. This parameter is called a type token. Unfortunately, type tokens themselves must always be reifiable (because you can't get a Class object for a non-reifiable type) which can limit their usefulness.

like image 181
scottb Avatar answered Oct 25 '22 23:10

scottb