1

As far as I know, type generics happens in the following code:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

when the compiler compiles the code, the generic types will be erased so all the signatures are exactly same, which looks as follows:

public class Test {

    public void a(List list) {
    }

    public void a(List list){
    }

    public void a(List list){
    }

}

If this is the logic, then:

List<Object> objList = new ArrayList<>();
List<String> strList = new ArrayList<>();
objList = strList;  

is actually:

List objList = new ArrayList<>();
List strList = new ArrayList<>();
objList = strList; 

which is OK because both of the two lists are same type. However, In the above code, objList = strList will result an error.

Not quite sure what is the real logic. And what is more, the difference between List<?>, List(without any braces) and List< Object>

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
Lake_Lagunita
  • 521
  • 1
  • 4
  • 20
  • 6
    Because type erasure happens after compilation; the compiler prevents `objList = strList;`. Thus it is not a problem. Also that is basically the point of generic types. To prevent `objList = strList` at compile time. Type erasure is a side effect of the implementation. – Elliott Frisch Aug 07 '21 at 16:18
  • Does this answer your question? [Java generics type erasure: when and what happens?](https://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens) – Joe Aug 15 '21 at 14:42

4 Answers4

1

To complement @Giorgi Tsiklauri's answer,

For the class below:

class Box<T> {
    T t;

    T getT() { return t; }

    void setT(T t) { this.t = t; }
}

because of type erasure, compiler compiles the class to:

class Box {
    Object t;

    Object getT() { return t; }

    void setT(Object t) { this.t = t; }
}

So, when you instantiate the Box<T> generic class with type argument Integer as follows:

Box<Integer> box = new Box<Integer>();
box.setT(10);
Integer t = box.getT();

the compiler knows that the Box<T> is instantiated with Integer because, at compile time, it sees that Box<Integer>. So, type casts are inserted by compiler. So the code above is compiled into:

Box box = new Box();
box.setT(10);
Integer t = (Integer) box.getT(); // compiler inserts type casts in lieu of us!

No matter how you instantiate the generic, the compiler doesn't create additional class files. If what actually happens at type erasure is replacement(replaces T with type argument such as Integer), the compiler have to create additional classes for Box for Integer, Box for Double etc — But that's not what actually happens at type erasure:

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. — The Java™ Tutorials

Insert type casts if necessary to preserve type safety. — The Java™ Tutorials

Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead. — The Java™ Tutorials

rosshjb
  • 581
  • 1
  • 8
  • 26
0

Generics are invariant: for any two distinct types U and V, List<U> is neither a subtype nor a supertype of List<V>. (Joshua Bloch, Effective Java)

You can't put any value except null into a List<?>.

grigouille
  • 511
  • 3
  • 14
0

The diff between List<?> and List is the former can take any type either an Object class or any other object. The latter can take only object

List<Object> list = new ArrayList<String> // compile error

List<?> list = new ArrayList<String>  //no error

List<?extends Comparator> (boundedd) will get converted to List after compile List Unbounded are converted to Object whereas for bounded the Java compiler replaces the bounded type parameter T with the first bound class.

For more details Generics

  • so what is difference between List> list= new ArrayList() and List list= new ArrayList() – Lake_Lagunita Aug 07 '21 at 17:23
  • 1
    List> list = new ArrayList(); list.add(1.1); //Compile error List list1 = new ArrayList(); list1.add(1.1); /No error In this example, the compiler processes the as being of type Object. When we call add method invokes the compiler is not able to confirm the type of object that is being inserted into the list, and an error is produced. – Ashish Purohit Aug 07 '21 at 17:36
-1

If this is the logic, then..

No, that is not what happens.

Type erasure is a process that takes place during compilation, and for specific object allocations (objects, created using new), compiler erases all the generic type parameters (e.g. Box<T>) with corresponding generic type arguments (e.g. Box<Integer>).

This means, that if you have defined your class:

class Box<T> {
}

and then invoked that type (instantiated), as:

Box<Integer> intBox = new Box<>();

in the compiled version, instantiation of intBox will allocate the object, on the heap, having swapped all the appearances of T with Integer.

Therefore, in your example:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

you are invoking a parametrized type (generic) and you declare method's local parameter with generic type argument.

For the object referenced by the variable of type List<String>, compiler have erased all the appearances of List's E with String, and for List<Integer> - E will be replaced by Integer.

For the final part of your confusion, I'd suggest you read this.

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
  • Wrong: For the `Box`, the `T` is replaced by `Object`, **not `Integer`**. If you use the generic type `Box` as `Box`, you just get `Box`. But, to provide type safety, the compiler inserts type casts. For example, `Integer value = box.getValue();` is converted to `Integer value = (Integer)box.getValue();`(Yes, the getter returns `Object`, not `Integer`), assuming that there are member `T value;` and its getter. For the information, read [this](https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html) – rosshjb Dec 13 '21 at 06:01
  • @rosshjb did you read the text carefully? I don't think so, but you've rushed into downvote. e.g. means "for example", and not always. "compiler erases all the generic type parameters (e.g. Box) with corresponding generic type arguments (e.g. Box)" - is what I say. Moreover, after that I give an example of `Box` which is indeed a case of type erasure with Integer. So, what's wrong? – Giorgi Tsiklauri Dec 28 '21 at 08:32
  • You are saying that type params are replaced by type args, on and on. See the statements you wrote `"E will be replaced by Integer."` or `"having swapped all the appearances of T with Integer"` — That's not actually happened in type erasure. For `class Box {}` and `Box box;`, the compiler erases type parameters and type arguments, and they are compiled to `class Box {}` and `Box box`(raw type) respectively. At the use site, the compiler knows that the `box` is instantiated with type argument `Integer` so type cast would be inserted like `Integer value = (Integer)box.getValue();`. – rosshjb Dec 28 '21 at 11:18
  • After type erasure, type parameters and type arguments all are gone. Actually, "replacement" also doesn't happen too. Type erasure erases, not replaces, the things. After type erasure, just `Object`(for raw type) is left to support backward compatibility. – rosshjb Dec 28 '21 at 11:24
  • I wrote an answer with more specific example. If my downvote to your answer hurts you, you can downvote [my answer](https://stackoverflow.com/a/70506699/9304999) too. I just wanted to correct your answer. – rosshjb Dec 28 '21 at 11:57