Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic type in getConstructors() in Class

In the generic class Class<T> the method getConstructors() has a return type with unknown generic type parameter instead of T. The reason for this is explainend in the javadoc.

Note that while this method returns an array of Constructor<T> objects (that is an array of constructors from this class), the return type of this method is Constructor<?>[] and not Constructor<T>[] as might be expected. This less informative return type is necessary since after being returned from this method, the array could be modified to hold Constructor objects for different classes, which would violate the type guarantees of Constructor<T>[].

A colleague of mine and I have tried to understand that explanation. In our understanding they are basically saying that it is of unknown generic type, because some caller could put other Constructor objects into that array. Did we get that right? And if so, why would someone design an API this way. Wouldn't it be better to use the specific type and trust the programmer to use the array correctly? To us it sounds a little like "We are making a worse API because the programmer using it might try something stupid". Where lies our fallacy?

like image 504
André Stannek Avatar asked Jul 01 '14 13:07

André Stannek


People also ask

How do you declare a generic type in a class explain?

If we want the data to be of int type, the T can be replaced with Integer, and similarly for String, Character, Float, or any user-defined type. The declaration of a generic class is almost the same as that of a non-generic class except the class name is followed by a type parameter section.

What is the generic class type called?

These classes are known as parameterized classes or parameterized types because they accept one or more parameters.

What is the use of generic class?

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs.

What is type getconstructors () method in Java?

Returns: This method returns ConstructorInfo array objects representing all the public instance constructors defined for the current Type, but it does not include type initializer (static constructor). Below programs illustrate the use of Type.GetConstructors () Method: Example 1:

What is a generic constructor in Java?

A generic constructor is a constructor that has at least one parameter of a generic type. We'll see that generic constructors don't have to be in a generic class, and not all constructors in a generic class have to be generic. 2. Non-Generic Class First, we have a simple class Entry, which is not a generic class:

Does the entry class have a generic constructor?

Although the Entry class isn't generic, it has a generic constructor, as it has a parameter element of type E. The generic type E is bounded and should implement both Rankable and Serializable interfaces. Now, let's have a look at the Rankable interface, which has one method:

How to get the specified constructor of a class in Java?

The getConstructor () method of java.lang.Class class is used to get the specified constructor of this class with the specified parameter type, which is the constructor that is public and its members. The method returns the specified constructor of this class in the form of Constructor object.


2 Answers

It's the exact same reason why you are not allowed to do new Constructor<T>[], but you are allowed to do new Constructor<?>[]. You can apply your same argument and say "Wouldn't it be better to use the allow the specific type and trust the programmer to use the array correctly?" Well, Java decided no. (You can imagine that inside the getConstrucotrs method, they need to create an array of Constructor, and they cannot do new Constructor<T>[] but they can do new Constructor<?>[].)

Of course, you can make an unchecked cast of the Constructor<?>[] to the Constructor<T>[], but that will give you a warning in your code, in which case you would take responsibility for making sure it's safe. But if the getConstructors method this this unchecked cast in their code, you as the caller would never be warned about the unsafeness.

like image 200
newacct Avatar answered Oct 17 '22 14:10

newacct


The point that was mentioned by Ashu Pachauri in the comment (namely, that the array is returned for backward compatibility) is certainly valid. And in general, arrays and generics don't play together very well. (For evidence, look for all the stackoverflow questions related to "Generic Arrays"...)

Additionally, there is a rule that an API should be easy to use and hard to misuse. In this case, this is related to the Principle of least astonishment: Someone obtaining the constructors with this method could perform a perfectly legal sequence of operations on the returned array, and in the end, receive an unexpected ClassCastException. So one could say that the fact that a Constructor<?>[] array is returned aims at a "fail-fast" behavior.

An illustrative example:

import java.lang.reflect.Constructor;

public class GetConstructorsReturnType
{
    public static void main(String[] args) throws Exception
    {
        // This causes a warning, due to the cast, but imagine
        // this was possible
        Constructor<DerivedA> constructorsA[] =
            (Constructor<DerivedA>[])DerivedA.class.getConstructors();

        // The following lines are valid due to the subtype
        // relationship, but would not be valid if constructorsA
        // was declared as "Constructor<?>"
        Constructor<? extends Base> constructors[] = constructorsA;
        constructors[0] = DerivedB.class.getConstructor();

        // This causes a ClassCastException (and would also not
        // be possible constructorsA was declared as "Constructor<?>"
        DerivedA instance = constructorsA[0].newInstance();
    }
}
class Base
{
}
class DerivedA extends Base
{
    public DerivedA()
    {
    }
}
class DerivedB extends Base
{
    public DerivedB()
    {
    }
}
like image 3
Marco13 Avatar answered Oct 17 '22 13:10

Marco13