Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generic Wildcard Constructor not accepting objects?

I have a RandomizedWrapper class. This class contains a constructor that accepts a list:

public class RandomizedWrapper{

   final int upperBound = 100;
   final List<RandomizerEntry<?>> randomizeList;
   Map<Integer, RandomizerEntry<?>> randomizerMap;

/**
 * Construct a new RandomizedWrapper instance
 * 
 * @param randomizeList - A list containing all randomizable objects
 */
public RandomizedWrapper(final List<RandomizerEntry<?>> randomizeList) {
    
    this.randomizeList = randomizeList;
    this.randomizerMap = new HashMap<>();
   }
}

I want to create a new instance of this RandomizedWrapper class. I do via the following code:

    List<RandomizerEntry<ItemStack>> randomizerList = new ArrayList<>();

    //stuff here

    RandomizedWrapper wrapper = new RandomizedWrapper(randomizerList);//error

When I attempt to create this new object, I run into the following error:

The constructor RandomizedWrapper(List<RandomizerEntry<ItemStack>>) is undefined

This makes no sense. I very clearly have a constructor in the RandomizedWrapper class that accepts a List<RandomizerEntry<?>> wildcards. A proposed solution by the compiler says "create a constructor that accepts this argument". I click that, just to see what happens, and it tells me "This constructor already exists".

Does anyone understand whats going on here? Why can't I instantiate this object?

like image 674
Matthew Avatar asked Jan 06 '21 21:01

Matthew


People also ask

Can a generic class have constructor?

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.

How do you initialize a generic object in Java?

If you want to initialize Generic object, you need to pass Class<T> object to Java which helps Java to create generic object at runtime by using Java Reflection.

How do you use generic wildcards?

Guidelines for Wildcards. Upper bound wildcard − If a variable is of in category, use extends keyword with wildcard. Lower bound wildcard − If a variable is of out category, use super keyword with wildcard. Unbounded wildcard − If a variable can be accessed using Object class method then use an unbound wildcard.

What is the type meaning of the wildcard (?) In the context of Java generics?

Wildcards are nothing but the question mark(?) that you use in the Java Generics. We can use the Java Wildcard as a local variable, parameter, field or as a return type. But, when the generic class is instantiated or when a generic method is called, we can't use wildcards.


Video Answer


2 Answers

The issue here is that List<RandomizerEntry<ItemStack>> is not a subtype of List<RandomizerEntry<?>> so your constructor is not applicable to your argument. See this section of the Java tutorial which specifically addresses this misunderstanding.

As for the IDE suggestion to create another constructor, this won't work because in Java it is not possible to "overload a method where the formal parameter types of each overload erase to the same raw type" (details).

To solve the issue one way is simply to make the type of your local variable compatible with your constructor, although this will of course limit what you can do with it:

List<RandomizerEntry<?>> randomizerList = new ArrayList<>();
like image 148
SDJ Avatar answered Nov 06 '22 05:11

SDJ


? (wildcars) mostly used when the generic code doesn't require any reference to a type and RandomizedWrapper isn't type of class where wildcards are needed. In this case its preferable to use Type Parameter <T> (Difference between ? (wildcard) and Type Parameter in Java)

public class RandomizedWrapper<T>{

    final int upperBound = 100;
    final List<RandomizerEntry<T>> randomizeList;
    Map<Integer, RandomizerEntry<T>> randomizerMap;

    /**
     * Construct a new RandomizedWrapper instance
     *
     * @param randomizeList - A list containing all randomizable objects
     */
    public RandomizedWrapper(final List<RandomizerEntry<T>> randomizeList) {

        this.randomizeList = randomizeList;
        this.randomizerMap = new HashMap<>();
    }


    public void create(){
        List<RandomizerEntry<Integer>> randomizerList = new ArrayList<>();
        //stuff here
        RandomizedWrapper wrapper = new RandomizedWrapper(randomizerList);//OK
    }
}
like image 25
i.merkurev Avatar answered Nov 06 '22 05:11

i.merkurev