Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Why am I able to have a reference to a non-null array of concrete parameterized types?

I was surprised, but ... this compiles:

public <T extends Database> ColMetaData<T>[] getTableColumnsAsEnums() {
            Class<? extends ColMetaData> cls = this.columnsEnumToken();
            return cls.<ColMetaData<T>[]>getEnumConstants(); }

Here is the method for columnsEnumToken:

// Returns a class token for an enum class
public Class<? extends ColMetaData> columnsEnumToken()  { 
    return this.e_colsToken; 
}

(I guess I can see why the second line below doesn't compile)

Some questions:

  • Is this method "type safe"?

  • Why does this line compile:

    Class<? extends ColMetaData> cls = this.columnsEnumToken();

    But this one fails to compile because of incompatible types:

    Class<? extends ColMetaData<T>> cls = this.columnsEnumToken();

  • Why is it legal for method getTableColumnsAsEnums() to return an array of a concrete parameterized type, ColMetaData<T>[]. I had thought that these were strictly verboten because there was no runtime way to have them operate type safely.

like image 684
scottb Avatar asked Jun 13 '13 00:06

scottb


People also ask

Why does Java not allow generic arrays?

Java allows generic classes, methods, etc. that can be declared independent of types. However, Java does not allow the array to be generic. The reason for this is that in Java, arrays contain information related to their components and this information is used to allocate memory at runtime.

Why primitive data types are not allowed in Java generics?

Using generics, primitive types can not be passed as type parameters. In the example given below, if we pass int primitive type to box class, then compiler will complain. To mitigate the same, we need to pass the Integer object instead of int primitive type.

Can you create an array using a generic type parameter?

Array of generic typesNo, we cannot create an array of generic type objects if you try to do so, a compile time error is generated.


2 Answers

Class

Theoretically, a Class cannot represent a parameterized type. For example, there is no class for List<String>, so you should not write Class<List<String>>, but only Class<List>.

However Class<? extends List<String>> could make sense. For example, if we have

    public class MyStringList extends ArrayList<String>{}

MyStringList.class is a Class<MyStringList> which is a Class<? extends List<String>>

Generic Array

There's nothing wrong with generic array type, it's just that Java forbids us to instantiate any... But the reason isn't very convincing. You can just go ahead and create one through casts, as long as you know it's safe.

Actually, there is a straightforward way in Java to create a generic array. When we call a method with varargs X..., an X[] object will be created - and X can be any type.

Compatible assignment

Apparently for some backward compatibility reason, we can assign a List[] to List<String>[]. That's why you can return a ColMetaData[] object while the return type is ColMetaData<T>[].

like image 130
ZhongYu Avatar answered Nov 10 '22 12:11

ZhongYu


Think about what ColMetaData<T>[] represents. In Java, generics are strictly a compile time issue. At run time, they cease to exist. So what you're really telling the runtime is that you have an array of ColMetaData instances, which indeed is a concrete type. This is different, however, than using an arbitrary type for the array. The array type is still ColMetaData, and Java can determine this at compile time. Then the compiler needs only to track that the instances you store use the correct generic type.

like image 23
jpmc26 Avatar answered Nov 10 '22 13:11

jpmc26