493msi 493msi - 6 days ago 5
Java Question

Correct usage of generic wildcards

I am trying to get this code working for half an hour now and I do not know, how I should fix this. Everything else doesn't complain, but the compiler keeps screaming at me that

configurable.value
is not the same type as
configurable.defaultValue
. I am quite confused as
?
is supposed to be a wildcard, right?

I am pretty new to generics, so I am a bit lost. I did not find any solution yet.

Is there a solution, which does not produce any warnings or errors?

ConfigurationManager.class is here:

public class ConfigurationManager
{
private final List<Configurable<?>> config;

public ConfigurationManager()
{
config = new ArrayList<Configurable<?>>();
}

public void register(Configurable<?> entry)
{
this.config.add(entry);
}

public void resetAll()
{
for(Configurable<?> configurable : this.config)
{
//Problem here
//Type mismatch: cannot convert from capture#3-of ? to capture#2-of ?
configurable.value = configurable.defaultValue;
}
}
}


Configurable.class is here:

public class Configurable<T>
{
ResourceAddress address;
protected T value;
protected final T defaultValue;

public Configurable(ResourceAddress address, T defaultValue)
{
this.address = address;
this.defaultValue = defaultValue;
this.value = this.defaultValue;
}

public ResourceAddress getAddress()
{
return address;
}

public void setValue(T value)
{
this.value = value;
}

public T getValue()
{
return value;
}
}

Answer

The problem is that the compiler doesn't recognize that value and defaultValue belong to the same object, so it doesn't know they have the same type. One solution is to create a type-capturing helper method to call from your loop:

<T> void resetValue(Configurable<T> configurable) {
    configurable.value = configurable.defaultValue;
}

As @chrylis points out, a better solution would probably be to add an instance method to Configurable:

public void resetValue() {
    this.value = this.defaultValue;
}