3

I have a group of classes that all implement a validation interface which has the method isValid(). I want to put a group of objects--all of different classes--into an ArrayList, loop through them and call isValid() on each.

Here's my code

Email email = new email();
Address address = new Address();

ArrayList<? extends Validation> myValidationObjects = new ArrayList();

But when I try to do:

myValidationObjects.add(email);

I get:

The method add(capture#2-of ? extends Validation) in the type ArrayList is not applicable for the arguments (Email)

Both Email and Address implement Validation.

According to this document, I should be able to use extends for both interfaces and subclasses.

2
  • 2
    Why not to use ArrayList<Validation> without any extends? Commented Jan 4, 2013 at 20:35
  • 1
    ? extends Validation means some specific but unknown subclass of Validation. For all the compiler knows, it could be some other subclass completely unrelated to Email or Address. Commented Jan 4, 2013 at 20:37

4 Answers 4

7

List<? extends Validation> myValidationObjects

Incorrect reading

"myValidationObjects is list of objects that extend Validation."

Correct reading

"myValidationObjects can be a list of any type that extends Validation. For example, it could be a List<RangeValidation> or a List<RegexValidation>."

Since there is no object you can legitimately add to both a List<RangeValidation> and a List<RegexValidation>, Java prevents you to call add on a variable of such type.

Your case is in fact the simpler one: you need the definite type List<Validation>.

Sign up to request clarification or add additional context in comments.

Comments

5

You can use:

List<Validation> myValidationObjects = new ArrayList<>();           // Java 7
List<Validation> myValidationObjects = new ArrayList<Validation>(); // pre Java 7

Now you can add any instance of a class that implements Validation to that list.

Comments

2

The declaration ArrayList<? extends Validation> means a list of an unknown class that extends Validation. Email is not compatible with this unknown class.

You can use ArrayList<Validation> for your list.

Comments

2

If a generic class's T is <? extends Foo>, then the only thing you can pass to a method that takes T is null -- not any subclass that extends Foo.

The reason is that List<? extends Validation> doesn't mean "a list of things that extend Validation". You can get that with just List<Validation>. Instead, it means "a list of some type, such that that type extends Validation."

It's a subtle distinction, but basically the idea is that List<? extends T> is a subtype of List<T>, and you therefore don't want to be able to insert anything into it. Think of this case:

List<FooValidation> foos = new ArrayList<>();
List<? extends Validation> validations = foos; // this is allowed
validations.add(new BarValidation()); // not allowed! this is your question
FooValidation foo = foos.get(0);

If the third line were allowed, then the last line would throw a ClassCastException.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.