0

I am new to Java. As I known, It's basically the way that generics are implemented in Java via compiler trickery.

public Object doSomething(Object obj) {....}

public <T> T doSomething(T t) {....}

According to type erasion, the above two method is the same at runtime. The only different is the way we use this method, compiler will auto add type casting when we use generic method.

Foo newFoo = (Foo) my.doSomething(foo);

Similarly, when we use generic array in method, as the below shown:

public void <T> T[] f(T[] args){
  return args;
}
public void <T> Object[] f(Object[] args){
  return args;
}

I think the above two methods are same at runtime because of type erasion.

Integer[] a = {1, 2};
Integer[] b = test.f(a);

When I use this method, I think the generic method will throw an CaseException. When we pass a to test.f(a), the JVM cast Integer[] to Object[]. And when we get the result from this method, the JVM will also cast Object[] to Integer[] and this cast will throw an CaseException. because array in java is support covariant but not contravariant.

As a result, the above code works in both compile and runtime. There must be something wrong about my understanding. But I can not find out. Can anyone help me? Thank you!

david
  • 13
  • 4

1 Answers1

1

T stands for a concrete type and it is not substitute for Object. It carries the actual type with itself. So when you pass an Integer[] to that method it returns Integer[] and it works properly - the compiler knows the type.

With your second method when you have Object[] you get the behavior you expect - you can pass Integer[] to Object[] but you cannot do vice versa and you get the compiler error.

Working examples:

    public static <T> T[] f1(T[] args){
      return args;  //That one works because we return T[]
    }
    public static <T> T[] f2(Object[] args){
      return (T[])args;   //That one also works because we return T[]
    }

The next one doesn't work because we return Object[] which might be of type T but might be of another type - it doesn't compile

    public static Object[] f2(Object[] args){
      return args;  //Object[] is not T[]
    }
Veselin Davidov
  • 7,031
  • 1
  • 15
  • 23
  • The implement for generic in java is type erasion. You can see this link : https://stackoverflow.com/questions/313584/what-is-the-concept-of-erasure-in-generics-in-java] . If we do not constain the type parameter, compile will replace the T with Object. – david May 04 '18 at 07:55
  • It replaces T with Object compile time but carries metadata for the supplied class. And it will give compile error when you try to assign an object to a type which it is not. (integer is an object but object is not an integer). That meta data that protects us from such casting errors is exactly what generics are all about. Otherwise we could go with just Object like before java 5 – Veselin Davidov May 04 '18 at 07:56
  • T replaced by Object, but it will change the metadata. And this changed metadata avoid such casting error. Am I right? – david May 04 '18 at 08:05
  • Yes that meta data protects you from that casting errors - that's what generics are actually. Information for the compiler to check for type safety – Veselin Davidov May 04 '18 at 08:06