Domanda

public class GetResponse <T extends KeywordIdentifier>{

    private List<KeywordMetrics<T>> metrics = null;


public List<KeywordMetrics<T>> getMetrics(){
        return this.metrics;
    }

    public void setMetrics(List<KeywordMetrics<T>> metrics){
        this.metrics = metrics;
    }
}


public class AdWordsKeywordIdentifier extends KeywordIdentifier {
//body
}
public class BingKeywordIdentifierextends KeywordIdentifier {
//body
}


GetResponse<? extends KeywordIdentifier> result= new GetResponse<AdWordsKeywordIdentifier>();
List<KeywordMetrics<AdWordsKeywordIdentifier>> stats = getGoogleStats();
List<KeywordMetrics<BingKeywordIdentifier>> stats2 = getBingStats();
result.setMetrics(stats);
result.setMetrics(stats2);

result.setMetrics(stats) method produces compile error.

ERROR (The method setMetrics(List<KeywordMetrics<capture#2-of ?extends KeywordIdentifier>>) in the type GetResponse<capture#2-of ?extends KeywordIdentifier> is not applicable for the arguments(List<KeywordMetrics<AdWordsKeywordIdentifier>>)

Could you please explain me why is that and how I can fix it?

È stato utile?

Soluzione

You need to declare result as what it is, i.e., a GetResponse<AdWordsKeywordIdentifier>.

EDIT:

Looking at your change I see one big problem. You are trying to call the setMetrics method with two lists of two different types. You simply cannot do that. Since GetResponse is parameterized with T, the type of the elements in the list must be exactly T, that is, either AdWordsKeywordIdentifier or BingKeywordIdentifier, it can't be both. The compiler is complaining because GetResponse has type parameter ? extends KeywordIdentifier and it cannot possibly infer what the actual type parameter is, so it can't statically ensure type safety for the method calls to setMetrics, i.e., you will never be able to call it.

Not all is lost though. You have to make a choice: either leave your generic class as is and enforce strong typing at all times or you can make the class not generic and modify the metrics field as follows:

class GetResponse {

  private List<? extends KeywordMetrics<? extends KeywordIdentifier>> metrics = null;

  public List<? extends KeywordMetrics<? extends KeywordIdentifier>> getMetrics() {
    return this.metrics;
  }

  public void setMetrics(List<? extends KeywordMetrics<? extends KeywordIdentifier>> metrics) {
    this.metrics = metrics;
  }
}

which will now only work for your original snippet:

GetResponse result = new GetResponse();
List<KeywordMetrics<AdWordsKeywordIdentifier>> stats = new ArrayList<>();
List<KeywordMetrics<BingKeywordIdentifier>> stats2 = new ArrayList<>();    result.setMetrics(stats);
result.setMetrics(stats2);

It all depends on what you are trying to achieve. The code above is still type safe. Since you said you want your code "generic" you have to give up knowing the exact type of your list at compile time (it is now a list of ? extends KeywordMetrics<? extends KeywordIdentifier>).

Note that the double wildcard is required to make this compile. A List<KeywordMetrics<BingKeywordIdentifier>> is a List<? extends KeywordMetrics<? extends KeywordIdentifier>> but it is not a List<KeywordMetrics<? extends KeywordIdentifier>>.

Altri suggerimenti

You didn't declare variable result with the correct type parameterization. Therefore, the compiler can't guarantee that calling the setMetrics method with this list should work.

Changing it to

GetResponse<AdWordsKeywordIdentifier> result = ....

should fix it.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top