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?
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.
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.
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.
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.
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<>();
? (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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With