Aleksandar Savkov
Aleksandar Savkov

Reputation: 2984

Setting Java generics of iterators

I've noticed something funny Java does (or at least Netbeans) when I use classes implementing ArrayList and changing the generics type of the elements. I basically created an abstract class that extends ArrayList and some subclasses that are supposed to work with String objects (so something like ArrayList<String>). One of the things I did to try to achieve that was this:

public abstract class A extends ArrayList {
   ...
}
@Override
public abstract class B extends A {
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

Another one was this:

public abstract class A extends ArrayList {
   ...
}
public abstract class B<String> extends A {
   @Override
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

The first one overrides successfully the iterator() method assigning a String value to it. The other one somehow cancels out the type casting. The funny thing is that none of them works when it comes to for loops. This receives type Object instead of String.

for (String s : B) {
   ...
}

Do you have any idea why this happens and how can I fix it without implementing my own iterator?

Upvotes: 1

Views: 2102

Answers (4)

newacct
newacct

Reputation: 122439

OMG this is terrible:

public abstract class B<String> extends A {
   @Override
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

String is not the class String, rather, you are declaring a new type variable called String (like T) that shadows the class String

Upvotes: 0

Anish Dasappan
Anish Dasappan

Reputation: 415

Use composition instead of Inheritance

    public class A implements Iterable<String>{
        List<String> myList = new ArrayList<String>();
        //do operations on myList
        public Iterator<String> iterator() {
             return myList.iterator();
        }
    }

Upvotes: 1

AlexR
AlexR

Reputation: 115328

If you extend generic class you should care about generics. I mean that your declaration should look like

public abstract class A extends ArrayList<String> {
   ...
}

if you want to use strings or

public abstract class <T> A extends ArrayList<T> {
   ...
}

if you want your class to be generic.

In both cases you do not have to override iterator() method: you can invoke its from super class and it will return you "good" iterator. Your declaration is equivalent to

public abstract class A extends ArrayList<Object> {
   ...
}

This is the reason for "strange" behavior.

BTW may I ask you why are you extending ArrayList? It really sounds strange.

Upvotes: 0

Lucas
Lucas

Reputation: 14949

Not sure what you are trying to do but if I understand correctly you want a class that extends ArrayList and has a Generic type of String... Perhaps you are looking for this:

public abstract class A<T> extends ArrayList<T> {
    ...
}
public abstract class B extends A<String> {
    ...
}

Then in your code, this:

B myList = ...;
for ( String s : myList ) {
    ...
} 

Will work just fine. Though I think you could come up with a much better solution. Do you have more specifics about your problem?

Upvotes: 4

Related Questions