3

I know Java does not allow not Create Instances of Type Parameters. Many articles simply said "Type Erase" as the reason. But does type parameters initialization not occur before type erase? Is Type Erase the only reason? Here is a example:

public class GenObj {
    public static <E> void append(List<E> list) {
        E elem = new E();  // compile-time error
        list.add(elem);
    }
    public static main(){
        List<String> list= new ArrayList<String>();
        GenOjb.append<String>(list);
    }
}

When we call the generic method using GenOjb.append(list), I think the compiler will replace E in the method with String first and then do "Type Erase", is that correct? If so, as long as we have a way to ensure E does indeed have a default constructor, we should be able to create instance of type parameters. Can someone explain in more detail why Java does not allow creating instance of parameter type? Thanks.

Tomi Liang
  • 31
  • 1
  • 4

4 Answers4

4

It is instructive to ask: How would you do it without Generics?

Every program with Generics can be converted into an equivalent program without Generics by simply removing generic parameters and inserting casts in appropriate places. This is called type erasure. So, if you want to know if you can do it with Generics, you need to first ask if you can do it without Generics.

Without Generics, your program looks like this:

public class GenObj {
    public static void append(List list) {
        Object elem = // what goes here?
        list.add(elem);
    }
    public static main(){
        List list= new ArrayList();
        GenOjb.append(list);
    }
}
newacct
  • 119,665
  • 29
  • 163
  • 224
  • 2
    new Object() goes there in place of new E(). So it should be fine? – Diffy May 27 '15 at 18:09
  • @Diffy: No, it's not fine, because then you will have adding `Object` objects (objects whose actual runtime class is `Object`), which is not what you want. – newacct May 27 '15 at 19:26
  • 3
    @Diffy Assume that its allowed then when you do list.get you will be expecting to get object (of the type which you intended when you called append method) but what you will be getting is an Object. This object which got returned cannot be casted to the type which you would have mentioned when creating an ArrayList. – Sunil Oct 31 '16 at 05:25
  • @Sunil could you explain `why Object cannot be casted to type which we would have mentioned when creating an ArrayList`. Yes the `type parameter` will be Object but the list will be containing the type which we would have mentioned. – Yug Singh Oct 31 '18 at 04:34
3

Due to runtime type erasure, the type is not available to do anything with.

You can however pass a type token:

public static <E> void append(List<E> list, Class<E> c) {
    E elem = c.newInstance();
    list.add(elem);
}

This presupposes that the class has a no-args constructor.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • My point is when the method is called, the E was changed to String type before type erasure occurred. so the compiler could generate the byte code to create a String type instead. Or show me the type erasure process steps by steps. isn't the E will be replaced with String first before type erasure occurs in my code sample? – Tomi Liang Dec 27 '13 at 06:45
2

Remember that Generics are for compile time checking and that when you compile a class within .java file, Java produces a single .class file for that class.

When we call the generic method using GenOjb.append(list); I think compiler will replace E in the method with String first and then do "Type Erase", is that correct?

No, nothing is replaced in the method. Once the .class file is generated, that's what you get. When compiling, the compiler simply verifies that the String type is an acceptable type argument for the append() method. Since you've specified no bounds on E, the compiler judges that String is an acceptable type argument.

Can someone explain in more details why java not allow creating instance of parameter type?

That's just not how the java language works. Class instantiation happens at run time. At run time, there is no longer any notion of type variables because of type erasure and therefore we cannot know what E is.

There are a few alternatives for getting an instance of whatever type T ends up being. See here:

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
0

Because under the covers, a List<E> is just a List. The actual type that has been substituted for E is not passed on the stack. Therefore, when the JVM is running this code, there is no way to tell what type E is, so it has no way of knowing what class to instantiate.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110